Completed
Push — master ( 95e37c...1f9e9c )
by
unknown
03:55
created

Bpost::setApiCaller()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
namespace Bpost\BpostApiClient;
3
4
use Bpost\BpostApiClient\ApiCaller\ApiCaller;
5
use Psr\Log\LoggerInterface;
6
use Bpost\BpostApiClient\Bpost\CreateLabelInBulkForOrders;
7
use Bpost\BpostApiClient\Bpost\Labels;
8
use Bpost\BpostApiClient\Bpost\Order;
9
use Bpost\BpostApiClient\Bpost\Order\Box;
10
use Bpost\BpostApiClient\Bpost\Order\Box\Option\Insurance;
11
use Bpost\BpostApiClient\Bpost\ProductConfiguration;
12
use Bpost\BpostApiClient\Common\ValidatedValue\LabelFormat;
13
use Bpost\BpostApiClient\Exception\BpostApiResponseException\BpostCurlException;
14
use Bpost\BpostApiClient\Exception\BpostApiResponseException\BpostInvalidResponseException;
15
use Bpost\BpostApiClient\Exception\BpostApiResponseException\BpostInvalidSelectionException;
16
use Bpost\BpostApiClient\Exception\BpostLogicException\BpostInvalidValueException;
17
use Bpost\BpostApiClient\Exception\XmlException\BpostXmlInvalidItemException;
18
19
/**
20
 * Bpost class
21
 *
22
 * @author    Tijs Verkoyen <[email protected]>
23
 * @version   3.0.0
24
 * @copyright Copyright (c), Tijs Verkoyen. All rights reserved.
25
 * @license   BSD License
26
 */
27
class Bpost
28
{
29
30
    const LABEL_FORMAT_A4 = 'A4';
31
    const LABEL_FORMAT_A6 = 'A6';
32
33
    // URL for the api
34
    const API_URL = 'https://api.bpost.be/services/shm';
35
36
    // current version
37
    const VERSION = '3.3.0';
38
39
    /** Min weight, in grams, for a shipping */
40
    const MIN_WEIGHT = 0;
41
42
    /** Max weight, in grams, for a shipping */
43
    const MAX_WEIGHT = 30000;
44
45
    /** @var ApiCaller */
46
    private $apiCaller;
47
48
    /**
49
     * The account id
50
     *
51
     * @var string
52
     */
53
    private $accountId;
54
55
    /**
56
     * A cURL instance
57
     *
58
     * @var resource
59
     */
60
    private $curl;
61
62
    /**
63
     * The passPhrase
64
     *
65
     * @var string
66
     */
67
    private $passPhrase;
68
69
    /**
70
     * The port to use.
71
     *
72
     * @var int
73
     */
74
    private $port;
75
76
    /**
77
     * The timeout
78
     *
79
     * @var int
80
     */
81
    private $timeOut = 30;
82
83
    /**
84
     * The user agent
85
     *
86
     * @var string
87
     */
88
    private $userAgent;
89
90
    private $apiUrl;
91
92
    /** @var  Logger */
93
    private $logger;
94
95
    // class methods
96
    /**
97
     * Create Bpost instance
98
     *
99
     * @param string $accountId
100
     * @param string $passPhrase
101
     * @param string $apiUrl
102
     */
103
    public function __construct($accountId, $passPhrase, $apiUrl = self::API_URL)
104
    {
105
        $this->accountId = (string)$accountId;
106
        $this->passPhrase = (string)$passPhrase;
107
        $this->apiUrl = (string)$apiUrl;
108
        $this->logger = new Logger();
109
    }
110
111
    /**
112
     * @return ApiCaller
113
     */
114 View Code Duplication
    public function getApiCaller()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
115
    {
116
        if ($this->apiCaller === null) {
117
            $this->apiCaller = new ApiCaller(new Logger());
118
        }
119
        return $this->apiCaller;
120
    }
121
122
    /**
123
     * @param ApiCaller $apiCaller
124
     */
125
    public function setApiCaller(ApiCaller $apiCaller)
126
    {
127
        $this->apiCaller = $apiCaller;
128
    }
129
130
    /**
131
     * Destructor
132
     */
133
    public function __destruct()
134
    {
135
        if ($this->curl !== null) {
136
            curl_close($this->curl);
137
            $this->curl = null;
138
        }
139
    }
140
141
    /**
142
     * Decode the response
143
     *
144
     * @param  \SimpleXMLElement $item   The item to decode.
145
     * @param  array             $return Just a placeholder.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $return not be array|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
146
     * @param  int               $i      A internal counter.
147
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null?

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...
148
     * @throws BpostXmlInvalidItemException
149
     */
150
    private static function decodeResponse($item, $return = null, $i = 0)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
Unused Code introduced by
The parameter $i 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...
151
    {
152
        if (!$item instanceof \SimpleXMLElement) {
153
            throw new BpostXmlInvalidItemException();
154
        }
155
156
        $arrayKeys = array(
157
            'barcode',
158
            'orderLine',
159
            Insurance::INSURANCE_TYPE_ADDITIONAL_INSURANCE,
160
            Box\Option\Messaging::MESSAGING_TYPE_INFO_DISTRIBUTED,
161
            'infoPugo'
162
        );
163
        $integerKeys = array('totalPrice');
164
165
        /** @var \SimpleXMLElement $value */
166
        foreach ($item as $key => $value) {
167
            $attributes = (array)$value->attributes();
168
169
            if (!empty($attributes) && isset($attributes['@attributes'])) {
170
                $return[$key]['@attributes'] = $attributes['@attributes'];
171
            }
172
173
            // empty
174
            if (isset($value['nil']) && (string)$value['nil'] === 'true') {
175
                $return[$key] = null;
176
            } // empty
177
            elseif (isset($value[0]) && (string)$value == '') {
178
                if (in_array($key, $arrayKeys)) {
179
                    $return[$key][] = self::decodeResponse($value);
180
                } else {
181
                    $return[$key] = self::decodeResponse($value, null, 1);
182
                }
183
            } else {
184
                // arrays
185
                if (in_array($key, $arrayKeys)) {
186
                    $return[$key][] = (string)$value;
187
                } // booleans
188
                elseif ((string)$value == 'true') {
189
                    $return[$key] = true;
190
                } elseif ((string)$value == 'false') {
191
                    $return[$key] = false;
192
                } // integers
193
                elseif (in_array($key, $integerKeys)) {
194
                    $return[$key] = (int)$value;
195
                } // fallback to string
196
                else {
197
                    $return[$key] = (string)$value;
198
                }
199
            }
200
        }
201
202
        return $return;
203
    }
204
205
    /**
206
     * Make the call
207
     *
208
     * @param  string $url       The URL to call.
209
     * @param  string $body      The data to pass.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $body not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
210
     * @param  array  $headers   The headers to pass.
211
     * @param  string $method    The HTTP-method to use.
212
     * @param  bool   $expectXML Do we expect XML?
213
     * @return mixed
214
     * @throws BpostCurlException
215
     * @throws BpostInvalidResponseException
216
     * @throws BpostInvalidSelectionException
217
     */
218
    private function doCall($url, $body = null, $headers = array(), $method = 'GET', $expectXML = true)
219
    {
220
        // build Authorization header
221
        $headers[] = 'Authorization: Basic ' . $this->getAuthorizationHeader();
222
223
        // set options
224
        $options[CURLOPT_URL] = $this->apiUrl . '/' . $this->accountId . $url;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
225
        if ($this->getPort() != 0) {
226
            $options[CURLOPT_PORT] = $this->getPort();
227
        }
228
        $options[CURLOPT_USERAGENT] = $this->getUserAgent();
229
        $options[CURLOPT_RETURNTRANSFER] = true;
230
        $options[CURLOPT_TIMEOUT] = (int)$this->getTimeOut();
231
        $options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
232
        $options[CURLOPT_HTTPHEADER] = $headers;
233
234 View Code Duplication
        if ($method == 'POST') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
235
            $options[CURLOPT_POST] = true;
236
            $options[CURLOPT_POSTFIELDS] = $body;
237
        }
238
239
        $this->getApiCaller()->doCall($options);
240
241
        $response = $this->getApiCaller()->getResponseBody();
242
        $httpCode = $this->getApiCaller()->getResponseHttpCode();
243
        $contentType = $this->getApiCaller()->getResponseContentType();
244
245
        // valid HTTP-code
246
        if (!in_array($httpCode, array(0, 200, 201))) {
247
            // convert into XML
248
            $xml = @simplexml_load_string($response);
249
250
            // validate
251
            if ($xml !== false && (substr($xml->getName(), 0, 7) == 'invalid')
252
            ) {
253
                // message
254
                $message = (string)$xml->error;
255
                $code = isset($xml->code) ? (int)$xml->code : null;
256
257
                // throw exception
258
                throw new BpostInvalidSelectionException($message, $code);
259
            }
260
261
            $message = '';
262
            if (
263
                ($contentType !== null && substr_count($contentType, 'text/plain') > 0) ||
264
                (in_array($httpCode, array(400, 404)))
265
            ) {
266
                $message = $response;
267
            }
268
269
            throw new BpostInvalidResponseException($message, $httpCode);
270
        }
271
272
        // if we don't expect XML we can return the content here
273
        if (!$expectXML) {
274
            return $response;
275
        }
276
277
        // convert into XML
278
        $xml = simplexml_load_string($response);
279
280
        // return the response
281
        return $xml;
282
    }
283
284
    /**
285
     * Get the account id
286
     *
287
     * @return string
288
     */
289
    public function getAccountId()
290
    {
291
        return $this->accountId;
292
    }
293
294
    /**
295
     * Generate the secret string for the Authorization header
296
     *
297
     * @return string
298
     */
299
    private function getAuthorizationHeader()
300
    {
301
        return base64_encode($this->accountId . ':' . $this->passPhrase);
302
    }
303
304
    /**
305
     * Get the passPhrase
306
     *
307
     * @return string
308
     */
309
    public function getPassPhrase()
310
    {
311
        return $this->passPhrase;
312
    }
313
314
    /**
315
     * Get the port
316
     *
317
     * @return int
318
     */
319
    public function getPort()
320
    {
321
        return (int)$this->port;
322
    }
323
324
    /**
325
     * Get the timeout that will be used
326
     *
327
     * @return int
328
     */
329
    public function getTimeOut()
330
    {
331
        return (int)$this->timeOut;
332
    }
333
334
    /**
335
     * Get the useragent that will be used.
336
     * Our version will be prepended to yours.
337
     * It will look like: "PHP Bpost/<version> <your-user-agent>"
338
     *
339
     * @return string
340
     */
341
    public function getUserAgent()
342
    {
343
        return (string)'PHP Bpost/' . self::VERSION . ' ' . $this->userAgent;
344
    }
345
346
    /**
347
     * Set the timeout
348
     * After this time the request will stop. You should handle any errors triggered by this.
349
     *
350
     * @param int $seconds The timeout in seconds.
351
     */
352
    public function setTimeOut($seconds)
353
    {
354
        $this->timeOut = (int)$seconds;
355
    }
356
357
    /**
358
     * Set the user-agent for you application
359
     * It will be appended to ours, the result will look like: "PHP Bpost/<version> <your-user-agent>"
360
     *
361
     * @param string $userAgent Your user-agent, it should look like <app-name>/<app-version>.
362
     */
363
    public function setUserAgent($userAgent)
364
    {
365
        $this->userAgent = (string)$userAgent;
366
    }
367
368
    // webservice methods
369
// orders
370
    /**
371
     * Creates a new order. If an order with the same orderReference already exists
372
     *
373
     * @param  Order $order
374
     *
375
     * @return bool
376
     * @throws BpostCurlException
377
     * @throws BpostInvalidResponseException
378
     * @throws BpostInvalidSelectionException
379
     */
380
    public function createOrReplaceOrder(Order $order)
381
    {
382
        $url = '/orders';
383
384
        $document = new \DOMDocument('1.0', 'utf-8');
385
        $document->preserveWhiteSpace = false;
386
        $document->formatOutput = true;
387
388
        $document->appendChild(
389
            $order->toXML(
390
                $document,
391
                $this->accountId
392
            )
393
        );
394
395
        $headers = array(
396
            'Content-type: application/vnd.bpost.shm-order-v3.3+XML'
397
        );
398
399
        return (
400
            $this->doCall(
401
                $url,
402
                $document->saveXML(),
403
                $headers,
404
                'POST',
405
                false
406
            ) == ''
407
        );
408
    }
409
410
    /**
411
     * Fetch an order
412
     *
413
     * @param $reference
414
     *
415
     * @return Order
416
     * @throws BpostCurlException
417
     * @throws BpostInvalidResponseException
418
     * @throws BpostInvalidSelectionException
419
     * @throws Exception\XmlException\BpostXmlNoReferenceFoundException
420
     */
421
    public function fetchOrder($reference)
422
    {
423
        $url = '/orders/' . (string)$reference;
424
425
        $headers = array(
426
            'Accept: application/vnd.bpost.shm-order-v3.3+XML',
427
        );
428
        $xml = $this->doCall(
429
            $url,
430
            null,
431
            $headers
432
        );
433
434
        return Order::createFromXML($xml);
0 ignored issues
show
Bug introduced by
It seems like $xml defined by $this->doCall($url, null, $headers) on line 428 can also be of type string; however, Bpost\BpostApiClient\Bpost\Order::createFromXML() does only seem to accept object<SimpleXMLElement>, 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...
435
    }
436
437
    /**
438
     * Get the products configuration
439
     *
440
     * @return ProductConfiguration
441
     * @throws BpostCurlException
442
     * @throws BpostInvalidResponseException
443
     * @throws BpostInvalidSelectionException
444
     */
445
    public function fetchProductConfig()
446
    {
447
        $url = '/productconfig';
448
449
        $headers = array(
450
            'Accept: application/vnd.bpost.shm-productConfiguration-v3.1+XML',
451
        );
452
        /** @var \SimpleXMLElement $xml */
453
        $xml = $this->doCall(
454
            $url,
455
            null,
456
            $headers
457
        );
458
459
        return ProductConfiguration::createFromXML($xml);
460
    }
461
462
    /**
463
     * Modify the status for an order.
464
     *
465
     * @param  string $reference The reference for an order
466
     * @param  string $status    The new status, allowed values are: OPEN, PENDING, CANCELLED, COMPLETED, ON-HOLD or PRINTED
467
     *
468
     * @return bool
469
     * @throws BpostCurlException
470
     * @throws BpostInvalidResponseException
471
     * @throws BpostInvalidSelectionException
472
     * @throws BpostInvalidValueException
473
     */
474
    public function modifyOrderStatus($reference, $status)
475
    {
476
        $status = strtoupper($status);
477
        if (!in_array($status, Box::getPossibleStatusValues())) {
478
            throw new BpostInvalidValueException('status', $status, Box::getPossibleStatusValues());
479
        }
480
481
        $url = '/orders/' . $reference;
482
483
        $document = new \DOMDocument('1.0', 'utf-8');
484
        $document->preserveWhiteSpace = false;
485
        $document->formatOutput = true;
486
487
        $orderUpdate = $document->createElement('orderUpdate');
488
        $orderUpdate->setAttribute('xmlns', 'http://schema.post.be/shm/deepintegration/v3/');
489
        $orderUpdate->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
490
        $orderUpdate->appendChild(
491
            $document->createElement('status', $status)
492
        );
493
        $document->appendChild($orderUpdate);
494
495
        $headers = array(
496
            'Content-type: application/vnd.bpost.shm-orderUpdate-v3+XML'
497
        );
498
499
        return (
500
            $this->doCall(
501
                $url,
502
                $document->saveXML(),
503
                $headers,
504
                'POST',
505
                false
506
            ) == ''
507
        );
508
    }
509
510
// labels
511
    /**
512
     * Get the possible label formats
513
     *
514
     * @return array
515
     */
516
    public static function getPossibleLabelFormatValues()
517
    {
518
        return array(
519
            self::LABEL_FORMAT_A4,
520
            self::LABEL_FORMAT_A6,
521
        );
522
    }
523
524
    /**
525
     * Generic method to centralize handling of labels
526
     *
527
     * @param  string $url
528
     * @param  string $format
529
     * @param  bool   $withReturnLabels
530
     * @param  bool   $asPdf
531
     *
532
     * @return Bpost\Label[]
533
     * @throws BpostCurlException
534
     * @throws BpostInvalidResponseException
535
     * @throws BpostInvalidSelectionException
536
     * @throws BpostInvalidValueException
537
     */
538
    protected function getLabel($url, $format = self::LABEL_FORMAT_A6, $withReturnLabels = false, $asPdf = false)
539
    {
540
        $format = strtoupper($format);
541
        if (!in_array($format, self::getPossibleLabelFormatValues())) {
542
            throw new BpostInvalidValueException('format', $format, self::getPossibleLabelFormatValues());
543
        }
544
545
        $url .= '/labels/' . $format;
546
        if ($withReturnLabels) {
547
            $url .= '/withReturnLabels';
548
        }
549
550
        if ($asPdf) {
551
            $headers = array(
552
                'Accept: application/vnd.bpost.shm-label-pdf-v3+XML',
553
            );
554
        } else {
555
            $headers = array(
556
                'Accept: application/vnd.bpost.shm-label-image-v3+XML',
557
            );
558
        }
559
560
        $xml = $this->doCall(
561
            $url,
562
            null,
563
            $headers
564
        );
565
566
        return Labels::createFromXML($xml);
0 ignored issues
show
Bug introduced by
It seems like $xml defined by $this->doCall($url, null, $headers) on line 560 can also be of type string; however, Bpost\BpostApiClient\Bpost\Labels::createFromXML() does only seem to accept object<SimpleXMLElement>, 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...
567
    }
568
569
    /**
570
     * Create the labels for all unprinted boxes in an order.
571
     * The service will return labels for all unprinted boxes for that order.
572
     * Boxes that were unprinted will get the status PRINTED, the boxes that
573
     * had already been printed will remain the same.
574
     *
575
     * @param  string $reference        The reference for an order
576
     * @param  string $format           The desired format, allowed values are: A4, A6
577
     * @param  bool   $withReturnLabels Should return labels be returned?
578
     * @param  bool   $asPdf            Should we retrieve the PDF-version instead of PNG
579
     *
580
     * @return Bpost\Label[]
581
     * @throws BpostInvalidValueException
582
     */
583
    public function createLabelForOrder(
584
        $reference,
585
        $format = self::LABEL_FORMAT_A6,
586
        $withReturnLabels = false,
587
        $asPdf = false
588
    ) {
589
        $url = '/orders/' . (string)$reference;
590
591
        return $this->getLabel($url, $format, $withReturnLabels, $asPdf);
592
    }
593
594
    /**
595
     * Create a label for a known barcode.
596
     *
597
     * @param  string $barcode          The barcode of the parcel
598
     * @param  string $format           The desired format, allowed values are: A4, A6
599
     * @param  bool   $withReturnLabels Should return labels be returned?
600
     * @param  bool   $asPdf            Should we retrieve the PDF-version instead of PNG
601
     *
602
     * @return Bpost\Label[]
603
     * @throws BpostInvalidValueException
604
     */
605
    public function createLabelForBox(
606
        $barcode,
607
        $format = self::LABEL_FORMAT_A6,
608
        $withReturnLabels = false,
609
        $asPdf = false
610
    ) {
611
        $url = '/boxes/' . (string)$barcode;
612
613
        return $this->getLabel($url, $format, $withReturnLabels, $asPdf);
614
    }
615
616
    /**
617
     * Create labels in bulk, according to the list of order references and the
618
     * list of barcodes. When there is an order reference specified in the
619
     * request, the service will return a label of every box of that order. If
620
     * a certain box was not yet printed, it will have the status PRINTED
621
     *
622
     * @param  array  $references       The references for the order
623
     * @param  string $format           The desired format, allowed values are: A4, A6
624
     * @param  bool   $withReturnLabels Should return labels be returned?
625
     * @param  bool   $asPdf            Should we retrieve the PDF-version instead of PNG
626
     *
627
     * @return Bpost\Label[]
628
     * @throws BpostCurlException
629
     * @throws BpostInvalidResponseException
630
     * @throws BpostInvalidSelectionException
631
     * @throws BpostInvalidValueException
632
     */
633
    public function createLabelInBulkForOrders(
634
        array $references,
635
        $format = LabelFormat::FORMAT_A6,
636
        $withReturnLabels = false,
637
        $asPdf = false
638
    ) {
639
        $createLabelInBulkForOrders = new CreateLabelInBulkForOrders();
640
641
        $xml = $this->doCall(
642
            $createLabelInBulkForOrders->getUrl(new LabelFormat($format), $withReturnLabels),
643
            $createLabelInBulkForOrders->getXml($references),
644
            $createLabelInBulkForOrders->getHeaders($asPdf),
645
            'POST'
646
        );
647
648
        return Labels::createFromXML($xml);
0 ignored issues
show
Bug introduced by
It seems like $xml defined by $this->doCall($createLab...eaders($asPdf), 'POST') on line 641 can also be of type string; however, Bpost\BpostApiClient\Bpost\Labels::createFromXML() does only seem to accept object<SimpleXMLElement>, 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...
649
    }
650
651
    /**
652
     * Set a logger to permit to the plugin to log events
653
     *
654
     * @param LoggerInterface $logger
655
     */
656
    public function setLogger(LoggerInterface $logger)
657
    {
658
        $this->logger->setLogger($logger);
659
    }
660
661
    /**
662
     * @param int $weight in grams
663
     * @return bool
664
     */
665
    public function isValidWeight($weight)
666
    {
667
        return self::MIN_WEIGHT <= $weight && $weight <= self::MAX_WEIGHT;
668
    }
669
}
670