Tracker   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 143
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 63.83%

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 1
dl 0
loc 143
ccs 30
cts 47
cp 0.6383
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A validTrackingNumber() 0 8 2
A track() 0 12 2
B queryAPI() 0 26 4
B processResponse() 0 25 5
1
<?php
2
3
/**
4
 * Copyright (c) 2014, Gustavo Henrique Mascarenhas Machado
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions are met:
9
 *
10
 * * Redistributions of source code must retain the above copyright notice, this
11
 *   list of conditions and the following disclaimer.
12
 *
13
 * * Redistributions in binary form must reproduce the above copyright notice,
14
 *   this list of conditions and the following disclaimer in the documentation
15
 *   and/or other materials provided with the distribution.
16
 *
17
 * * Neither the name of CorreiosAPI nor the names of its
18
 *   contributors may be used to endorse or promote products derived from
19
 *   this software without specific prior written permission.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
 */
32
33
namespace CorreiosAPI;
34
35
use Exception;
36
use InvalidArgumentException;
37
use RuntimeException;
38
use GuzzleHttp\Client as HttpClient;
39
40
class Tracker
41
{
42
  /**
43
   * Webservice endpoint
44
   */
45
  const WEBSERVICE_URL = 'https://webservice.correios.com.br/service/rastro/Rastro.wsdl';
46
47
  /**
48
   * Fetches a single package
49
   */
50
  const FETCH_SINGLE = 'L';
51
52
  /**
53
   * Fetches an interval of packages
54
   */
55
  const FETCH_INTERVAL = 'F';
56
57
  /**
58
   * The results mode. 'T' will return the entire package history.
59
   */
60
  const RESULT_MODE = 'T';
61
62
  /**
63
   * Webservice username, supplied by Correios
64
   * @var string
65
   */
66
  protected $username;
67
68
  /**
69
   * Webservice password, supplied by Correios
70
   * @var string
71
   */
72
  protected $password;
73
74
75
  /**
76
   * Sets up user credentials
77
   * @param  string $username Webservice username
78
   * @param  string $password Webservice password
79
   */
80 6
  public function __construct($username, $password)
81
  {
82 6
    $this->username = $username;
83 6
    $this->password = $password;
84 6
  }
85
86
  /**
87
   * Validates the format of a tracking number
88
   * @param  string $trackingNumber The tracking number
89
   * @return boolean
90
   */
91 6
  protected function validTrackingNumber($trackingNumber)
92
  {
93 6
    if (preg_match('/^[\D]{2}[\d]{9}[\D]{2}$/i', $trackingNumber)) {
94 1
      return true;
95
    }
96
97 5
    throw new InvalidArgumentException("{$trackingNumber} is not a valid tracking number in the format XX000000000YY.");
98
  }
99
100
  /**
101
   * Tracks one or more packages
102
   * @param  mixed $trackingNumber A single tracking number or an array of tracking numbers
103
   * @return mixed
104
   */
105 6
  public function track($trackingNumber)
106
  {
107 6
    if (is_array($trackingNumber)) {
108
      throw new \RuntimeException('Only a single tracking number can be processed at a time.');
109
    }
110
111 6
    $trackingNumber = strtoupper($trackingNumber);
112
113 6
    $this->validTrackingNumber($trackingNumber);
114
115 1
    return $this->queryAPI($trackingNumber, self::FETCH_SINGLE);
116
  }
117
118
  /**
119
   * Queries the Correios webservice
120
   * @param  string $trackingNumbers A collection of tracking numbers
121
   * @param  string $fetchMode       The fetch mode (for one or more tracking numbers)
122
   * @return mixed
123
   */
124 1
  protected function queryAPI($trackingNumbers, $fetchMode)
125
  {
126
    $params = [
127 1
        'usuario'   => $this->username
128 1
      , 'senha'     => $this->password
129 1
      , 'tipo'      => $fetchMode
130 1
      , 'resultado' => self::RESULT_MODE
131 1
      , 'objetos'   => $trackingNumbers
132 1
      , 'lingua'    => '101'
133 1
    ];
134
135
    try {
136 1
      $client = new \SoapClient(self::WEBSERVICE_URL);
137 1
      $response = $client->buscaEventos($params);
138
139 1
      if (!$response || empty($response)) {
140
        return false;
141
      }
142
143 1
      return $this->processResponse($response);
144 1
    } catch (Exception $e) {
145 1
      throw new RuntimeException($e->getMessage());
146
    }
147
148
    return false;
0 ignored issues
show
Unused Code introduced by
return false; 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...
149
  }
150
151
  /**
152
   * Processes the webservice response and builds a readable associative
153
   * array of the events associated to one or more packages
154
   * @param  string $responseBody The response body (xml)
155
   * @return mixed
156
   */
157 1
  protected function processResponse($responseBody)
158
  {
159 1
    $response = $responseBody->{'return'};
160
161 1
    if (!$response || $response->objeto->erro) {
162
      return false;
163
    }
164
165
    $results = [];
166
    $events = [];
167
168
    foreach ($response->objeto->evento as $event) {
169
      $events[] = [
170
          'when'    => $event->data . ' ' . $event->hora
171
        , 'where'   => strtoupper($event->local . (strlen($event->cidade) ? (' - ' . $event->cidade . '/' . $event->uf) : ''))
172
        , 'action'  => Tracker\ResponseCodes::getMessage($event->tipo, $event->status)
173
        , 'details' => (string) $event->descricao
174
      ];
175
    }
176
177
    $trackingNumber = (string) $response->objeto->numero;
178
    $results[$trackingNumber] = $events;
179
180
    return $results;
181
  }
182
}
183