Completed
Push — master ( abba19...1cc20b )
by Dennis
16:52
created

Ares   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 377
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 34.38%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 40
c 4
b 0
f 0
lcom 1
cbo 5
dl 0
loc 377
ccs 55
cts 160
cp 0.3438
rs 8.2608

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 18 4
A setBalancer() 0 6 1
A wrapUrl() 0 10 2
A getLastUrl() 0 4 1
B findInResById() 0 51 6
B findVatById() 0 45 6
C findByName() 0 52 8
A setCacheStrategy() 0 4 1
A setDebug() 0 4 1
A ensureIdIsInteger() 0 6 2
C findByIdentificationNumber() 0 65 8

How to fix   Complexity   

Complex Class

Complex classes like Ares often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Ares, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Defr;
4
5
use Defr\Ares\AresException;
6
use Defr\Ares\AresRecord;
7
use Defr\Ares\AresRecords;
8
use Defr\Ares\TaxRecord;
9
use InvalidArgumentException;
10
11
/**
12
 * Class Ares.
13
 *
14
 * @author Dennis Fridrich <[email protected]>
15
 */
16
class Ares
17
{
18
    const URL_BAS = 'http://wwwinfo.mfcr.cz/cgi-bin/ares/darv_bas.cgi?ico=%s';
19
    const URL_RES = 'http://wwwinfo.mfcr.cz/cgi-bin/ares/darv_res.cgi?ICO=%s';
20
    const URL_TAX = 'http://wwwinfo.mfcr.cz/cgi-bin/ares/ares_es.cgi?ico=%s&filtr=0';
21
    const URL_FIND = 'http://wwwinfo.mfcr.cz/cgi-bin/ares/ares_es.cgi?obch_jm=%s&obec=%s&filtr=0';
22
23
    /**
24
     * @var string
25
     */
26
    private $cacheStrategy = 'YW';
27
28
    /**
29
     * @var string
30
     */
31
    private $cacheDir = null;
32
33
    /**
34
     * @var bool
35
     */
36
    private $debug;
37
38
    /**
39
     * @var string
40
     */
41
    private $balancer = null;
42
43
    /**
44
     * @var array
45
     */
46
    private $contextOptions = [
47
        'ssl' => [
48
            'verify_peer' => false,
49
            'verify_peer_name' => false,
50
        ],
51
    ];
52
53
    /**
54
     * @var string
55
     */
56
    private $lastUrl;
57
58
    /**
59
     * @param null $cacheDir
60
     * @param bool $debug
61
     */
62 3
    public function __construct($cacheDir = null, $debug = false, $balancer = null)
63
    {
64 3
        if (null === $cacheDir) {
65 3
            $cacheDir = sys_get_temp_dir();
66
        }
67
68 3
        if (null !== $balancer) {
69
            $this->balancer = $balancer;
70
        }
71
72 3
        $this->cacheDir = $cacheDir.'/defr/ares';
73 3
        $this->debug = $debug;
74
75
        // Create cache dirs if they doesn't exist
76 3
        if (!is_dir($this->cacheDir)) {
77 1
            mkdir($this->cacheDir, 0777, true);
78
        }
79 3
    }
80
81
    /**
82
     * @param $balancer
83
     *
84
     * @return $this
85
     */
86 1
    public function setBalancer($balancer)
87
    {
88 1
        $this->balancer = $balancer;
89
90 1
        return $this;
91
    }
92
93
    /**
94
     * @param $url
95
     *
96
     * @return mixed
97
     */
98 3
    private function wrapUrl($url)
99
    {
100 3
        if ($this->balancer) {
101 1
            $url = sprintf('%s?url=%s', $this->balancer, urlencode($url));
102
        }
103
104 3
        $this->lastUrl = $url;
105
106 3
        return $url;
107
    }
108
109
    /**
110
     * @return string
111
     */
112 1
    public function getLastUrl()
113
    {
114 1
        return $this->lastUrl;
115
    }
116
117
    /**
118
     * @param $id
119
     *
120
     * @throws InvalidArgumentException
121
     * @throws Ares\AresException
122
     *
123
     * @return AresRecord
124
     */
125 3
    public function findByIdentificationNumber($id)
126
    {
127 3
        $id = Lib::toInteger($id);
128 3
        $this->ensureIdIsInteger($id);
129
130 3
        $cachedFileName = $id.'_'.date($this->cacheStrategy).'.php';
131 3
        $cachedFile = $this->cacheDir.'/bas_'.$cachedFileName;
132 3
        $cachedRawFile = $this->cacheDir.'/bas_raw_'.$cachedFileName;
133
134 3
        if (is_file($cachedFile)) {
135
            return unserialize(file_get_contents($cachedFile));
136
        }
137
138
        // Sestaveni URL
139 3
        $url = $this->wrapUrl(sprintf(self::URL_BAS, $id));
140
141
        try {
142 3
            $aresRequest = file_get_contents($url, null, stream_context_create($this->contextOptions));
143 2
            if ($this->debug) {
144
                file_put_contents($cachedRawFile, $aresRequest);
145
            }
146 2
            $aresResponse = simplexml_load_string($aresRequest);
147
148 2
            if ($aresResponse) {
149 2
                $ns = $aresResponse->getDocNamespaces();
150 2
                $data = $aresResponse->children($ns['are']);
151 2
                $elements = $data->children($ns['D'])->VBAS;
0 ignored issues
show
Bug introduced by
The property VBAS does not seem to exist in SimpleXMLElement.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
152
153 2
                $ico = (int) $elements->ICO;
154 2
                if ($ico !== $id) {
155
                    throw new AresException('IČ firmy nebylo nalezeno.');
156
                }
157
158 2
                $record = new AresRecord();
159
160 2
                $record->setCompanyId($id);
161 2
                $record->setTaxId(strval($elements->DIC));
162 2
                $record->setCompanyName(strval($elements->OF));
163 2
                $record->setStreet(strval($elements->AA->NU));
164
165 1
                if (strval($elements->AA->CO)) {
166 1
                    $record->setStreetHouseNumber(strval($elements->AA->CD));
167 1
                    $record->setStreetOrientationNumber(strval($elements->AA->CO));
168
                } else {
169
                    $record->setStreetHouseNumber(strval($elements->AA->CD));
170
                }
171
172 1
                if (strval($elements->AA->NCO)) {
173 1
                    $record->setTown(strval($elements->AA->N.' - '.strval($elements->AA->NCO)));
174
                } else {
175
                    $record->setTown(strval($elements->AA->N));
176
                }
177
178 1
                $record->setZip(strval($elements->AA->PSC));
179
            } else {
180 1
                throw new AresException('Databáze ARES není dostupná.');
181
            }
182 2
        } catch (\Exception $e) {
183 2
            throw new AresException($e->getMessage());
184
        }
185
186 1
        file_put_contents($cachedFile, serialize($record));
187
188 1
        return $record;
189
    }
190
191
    /**
192
     * @param $id
193
     *
194
     * @throws InvalidArgumentException
195
     * @throws Ares\AresException
196
     *
197
     * @return AresRecord
198
     */
199
    public function findInResById($id)
200
    {
201
        $id = Lib::toInteger($id);
202
        $this->ensureIdIsInteger($id);
203
204
        // Sestaveni URL
205
        $url = $this->wrapUrl(sprintf(self::URL_RES, $id));
206
207
        $cachedFileName = $id.'_'.date($this->cacheStrategy).'.php';
208
        $cachedFile = $this->cacheDir.'/res_'.$cachedFileName;
209
        $cachedRawFile = $this->cacheDir.'/res_raw_'.$cachedFileName;
210
211
        if (is_file($cachedFile)) {
212
            return unserialize(file_get_contents($cachedFile));
213
        }
214
215
        try {
216
            $aresRequest = file_get_contents($url, null, stream_context_create($this->contextOptions));
217
            if ($this->debug) {
218
                file_put_contents($cachedRawFile, $aresRequest);
219
            }
220
            $aresResponse = simplexml_load_string($aresRequest);
221
222
            if ($aresResponse) {
223
                $ns = $aresResponse->getDocNamespaces();
224
                $data = $aresResponse->children($ns['are']);
225
                $elements = $data->children($ns['D'])->Vypis_RES;
0 ignored issues
show
Bug introduced by
The property Vypis_RES does not seem to exist in SimpleXMLElement.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
226
227
                if (strval($elements->ZAU->ICO) === $id) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of strval($elements->ZAU->ICO) (string) and $id (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
228
                    $record = new AresRecord();
229
                    $record->setCompanyId(strval($id));
230
                    $record->setTaxId($this->findVatById($id));
231
                    $record->setCompanyName(strval($elements->ZAU->OF));
232
                    $record->setStreet(strval($elements->SI->NU));
233
                    $record->setStreetHouseNumber(strval($elements->SI->CD));
234
                    $record->setStreetOrientationNumber(strval($elements->SI->CO));
235
                    $record->setTown(strval($elements->SI->N));
236
                    $record->setZip(strval($elements->SI->PSC));
237
                } else {
238
                    throw new AresException('IČ firmy nebylo nalezeno.');
239
                }
240
            } else {
241
                throw new AresException('Databáze ARES není dostupná.');
242
            }
243
        } catch (\Exception $e) {
244
            throw new AresException($e->getMessage());
245
        }
246
        file_put_contents($cachedFile, serialize($record));
247
248
        return $record;
249
    }
250
251
    /**
252
     * @param $id
253
     *
254
     * @throws InvalidArgumentException
255
     * @throws \Exception
256
     *
257
     * @return TaxRecord|mixed
258
     */
259
    public function findVatById($id)
260
    {
261
        $id = Lib::toInteger($id);
262
263
        $this->ensureIdIsInteger($id);
264
265
        // Sestaveni URL
266
        $url = $this->wrapUrl(sprintf(self::URL_TAX, $id));
267
268
        $cachedFileName = $id.'_'.date($this->cacheStrategy).'.php';
269
        $cachedFile = $this->cacheDir.'/tax_'.$cachedFileName;
270
        $cachedRawFile = $this->cacheDir.'/tax_raw_'.$cachedFileName;
271
272
        if (is_file($cachedFile)) {
273
            return unserialize(file_get_contents($cachedFile));
274
        }
275
276
        try {
277
            $vatRequest = file_get_contents($url, null, stream_context_create($this->contextOptions));
278
            if ($this->debug) {
279
                file_put_contents($cachedRawFile, $vatRequest);
280
            }
281
            $vatResponse = simplexml_load_string($vatRequest);
282
283
            if ($vatResponse) {
284
                $record = new TaxRecord();
0 ignored issues
show
Bug introduced by
The call to TaxRecord::__construct() misses a required argument $taxId.

This check looks for function calls that miss required arguments.

Loading history...
285
                $ns = $vatResponse->getDocNamespaces();
286
                $data = $vatResponse->children($ns['are']);
287
                $elements = $data->children($ns['dtt'])->V->S;
288
289
                if (strval($elements->ico) === $id) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of strval($elements->ico) (string) and $id (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
290
                    $record->setTaxId(str_replace('dic=', 'CZ', strval($elements->p_dph)));
0 ignored issues
show
Bug introduced by
The method setTaxId() does not seem to exist on object<Defr\Ares\TaxRecord>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
291
                } else {
292
                    throw new AresException('DIČ firmy nebylo nalezeno.');
293
                }
294
            } else {
295
                throw new AresException('Databáze MFČR není dostupná.');
296
            }
297
        } catch (\Exception $e) {
298
            throw new \Exception($e->getMessage());
299
        }
300
        file_put_contents($cachedFile, serialize($record));
301
302
        return $record;
303
    }
304
305
    /**
306
     * @param $name
307
     * @param null $city
308
     *
309
     * @throws InvalidArgumentException
310
     * @throws \Exception
311
     *
312
     * @return array|AresRecord[]|AresRecords
313
     */
314
    public function findByName($name, $city = null)
315
    {
316
        if (strlen($name) < 3) {
317
            throw new InvalidArgumentException('Zadejte minimálně 3 znaky pro hledání.');
318
        }
319
320
        $url = $this->wrapUrl(sprintf(
321
            self::URL_FIND,
322
            urlencode(Lib::stripDiacritics($name)),
323
            urlencode(Lib::stripDiacritics($city))
324
        ));
325
326
        $cachedFileName = date($this->cacheStrategy).'_'.md5($name.$city).'.php';
327
        $cachedFile = $this->cacheDir.'/find_'.$cachedFileName;
328
        $cachedRawFile = $this->cacheDir.'/find_raw_'.$cachedFileName;
329
330
        if (is_file($cachedFile)) {
331
            return unserialize(file_get_contents($cachedFile));
332
        }
333
334
        $aresRequest = file_get_contents($url, null, stream_context_create($this->contextOptions));
335
        if ($this->debug) {
336
            file_put_contents($cachedRawFile, $aresRequest);
337
        }
338
        $aresResponse = simplexml_load_string($aresRequest);
339
        if (!$aresResponse) {
340
            throw new AresException('Databáze ARES není dostupná.');
341
        }
342
343
        $ns = $aresResponse->getDocNamespaces();
344
        $data = $aresResponse->children($ns['are']);
345
        $elements = $data->children($ns['dtt'])->V->S;
346
347
        if (!count($elements)) {
348
            throw new AresException('Nic nebylo nalezeno.');
349
        }
350
351
        $records = new AresRecords();
352
        foreach ($elements as $element) {
353
            $record = new AresRecord();
354
            $record->setCompanyId(strval($element->ico));
355
            $record->setTaxId(
356
                ($element->dph ? str_replace('dic=', 'CZ', strval($element->p_dph)) : '')
357
            );
358
            $record->setCompanyName(strval($element->ojm));
359
            //'adresa' => strval($element->jmn));
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
360
            $records[] = $record;
361
        }
362
        file_put_contents($cachedFile, serialize($records));
363
364
        return $records;
365
    }
366
367
    /**
368
     * @param string $cacheStrategy
369
     */
370
    public function setCacheStrategy($cacheStrategy)
371
    {
372
        $this->cacheStrategy = $cacheStrategy;
373
    }
374
375
    /**
376
     * @param bool $debug
377
     */
378
    public function setDebug($debug)
379
    {
380
        $this->debug = $debug;
381
    }
382
383
    /**
384
     * @param mixed $id
385
     */
386 3
    private function ensureIdIsInteger($id)
387
    {
388 3
        if (!is_int($id)) {
389
            throw new InvalidArgumentException('IČ firmy musí být číslo.');
390
        }
391 3
    }
392
}
393