Completed
Push — master ( 4b0c95...000b3f )
by Vítězslav
09:09
created

FlexiBeeRO::getExternalID()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 12
nc 4
nop 1
dl 0
loc 19
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * FlexiPeeHP - Read Only Access to FlexiBee class.
4
 *
5
 * @author     Vítězslav Dvořák <[email protected]>
6
 * @copyright  (C) 2015,2016 Spoje.Net
7
 */
8
9
namespace FlexiPeeHP;
10
11
class FlexiBeeRO extends \Ease\Brick
12
{
13
    /**
14
     * Základní namespace pro komunikaci s FlexiBee.
15
     * Basic namespace for communication with FlexiBee
16
     *
17
     * @var string Jmený prostor datového bloku odpovědi
18
     */
19
    public $nameSpace = 'winstrom';
20
21
    /**
22
     * Datový blok v poli odpovědi.
23
     * Data block in response field.
24
     *
25
     * @var string
26
     */
27
    public $resultField = 'results';
28
29
    /**
30
     * Verze protokolu použitého pro komunikaci.
31
     * Communication protocol version used.
32
     *
33
     * @var string Verze použitého API
34
     */
35
    public $protoVersion = '1.0';
36
37
    /**
38
     * Evidence užitá objektem.
39
     * Evidence used by object
40
     *
41
     * @link https://demo.flexibee.eu/c/demo/evidence-list Přehled evidencí
42
     * @var string
43
     */
44
    public $evidence = null;
45
46
    /**
47
     * Výchozí formát pro komunikaci.
48
     * Default communication format.
49
     *
50
     * @link https://www.flexibee.eu/api/dokumentace/ref/format-types Přehled možných formátů
51
     *
52
     * @var string json|xml|...
53
     */
54
    public $format = 'json';
55
56
    /**
57
     * Curl Handle.
58
     *
59
     * @var resource
60
     */
61
    public $curl = null;
62
63
    /**
64
     * @link https://demo.flexibee.eu/devdoc/company-identifier Identifikátor firmy
65
     * @var string
66
     */
67
    public $company = null;
68
69
    /**
70
     * Server[:port]
71
     * @var string
72
     */
73
    public $url = null;
74
75
    /**
76
     * REST API Username
77
     * @var string
78
     */
79
    public $user = null;
80
81
    /**
82
     * REST API Password
83
     * @var string
84
     */
85
    public $password = null;
86
87
    /**
88
     * @var array Pole HTTP hlaviček odesílaných s každým požadavkem
89
     */
90
    public $defaultHttpHeaders = ['User-Agent' => 'FlexiPeeHP v1.5'];
91
92
    /**
93
     * Default additional request url parameters after question mark
94
     * 
95
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls   Common params
96
     * @link https://www.flexibee.eu/api/dokumentace/ref/paging Paging params
97
     * @var array
98
     */
99
    public $defaultUrlParams = ['limit' => 0];
100
101
    /**
102
     * Identifikační řetězec.
103
     *
104
     * @var string
105
     */
106
    public $init = null;
107
108
    /**
109
     * Sloupeček s názvem.
110
     *
111
     * @var string
112
     */
113
    public $nameColumn = 'nazev';
114
115
    /**
116
     * Sloupeček obsahující datum vložení záznamu do shopu.
117
     *
118
     * @var string
119
     */
120
    public $myCreateColumn = 'false';
121
122
    /**
123
     * Slopecek obsahujici datum poslení modifikace záznamu do shopu.
124
     *
125
     * @var string
126
     */
127
    public $myLastModifiedColumn = 'lastUpdate';
128
129
    /**
130
     * Klíčový idendifikátor záznamu.
131
     *
132
     * @var string
133
     */
134
    public $fbKeyColumn = 'id';
135
136
    /**
137
     * Informace o posledním HTTP requestu.
138
     *
139
     * @var *
140
     */
141
    public $info;
142
143
    /**
144
     * Informace o poslední HTTP chybě.
145
     *
146
     * @var string
147
     */
148
    public $lastCurlError = null;
149
150
    /**
151
     * Used codes storage.
152
     *
153
     * @var array
154
     */
155
    public $codes = null;
156
157
    /**
158
     * Last Inserted ID.
159
     *
160
     * @var int
161
     */
162
    public $lastInsertedID = null;
163
164
    /**
165
     * Default Line Prefix.
166
     *
167
     * @var string
168
     */
169
    public $prefix = '/c/';
170
171
    /**
172
     * Raw Content of last curl response
173
     * 
174
     * @var string
175
     */
176
    public $lastCurlResponse;
177
178
    /**
179
     * HTTP Response code of last request
180
     *
181
     * @var int
182
     */
183
    public $lastResponseCode = null;
184
185
    /**
186
     * Array of fields for next curl POST operation
187
     *
188
     * @var array
189
     */
190
    protected $postFields = [];
191
192
    /**
193
     * Last operation result data or message(s)
194
     *
195
     * @var array
196
     */
197
    public $lastResult = null;
198
199
    /**
200
     * Nuber from  @rowCount
201
     * @var int
202
     */
203
    public $rowCount = null;
204
205
    /**
206
     * @link https://demo.flexibee.eu/devdoc/actions Provádění akcí
207
     * @var string
208
     */
209
    protected $action;
210
211
    /**
212
     * Pole akcí které podporuje ta která evidence
213
     * @link https://demo.flexibee.eu/c/demo/faktura-vydana/actions.json Např. Akce faktury
214
     * @var array
215
     */
216
    public $actionsAvailable = null;
217
218
    /**
219
     * Parmetry pro URL
220
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Všechny podporované parametry
221
     * @var array
222
     */
223
    public $urlParams = [
224
        'dry-run',
225
        'fail-on-warning',
226
        'report-name',
227
        'report-lang',
228
        'report-sign',
229
        'detail',
230
        'mode',
231
        'limit',
232
        'start',
233
        'order',
234
        'sort',
235
        'add-row-count',
236
        'relations',
237
        'includes',
238
        'use-ext-id',
239
        'use-internal-id',
240
        'stitky-as-ids',
241
        'only-ext-ids',
242
        'no-ext-ids',
243
        'no-ids',
244
        'code-as-id',
245
        'no-http-errors',
246
        'export-settings',
247
        'as-gui',
248
        'code-in-response',
249
        'add-global-version',
250
        'encoding',
251
        'delimeter',
252
        'format',
253
        'auth',
254
        'skupina-stitku',
255
        'dir',
256
        'xpath', // See: https://www.flexibee.eu/api/dokumentace/ref/xpath/
257
        'dry-run', // See: https://www.flexibee.eu/api/dokumentace/ref/dry-run/
258
        'inDesktopApp' // Note: Undocumented function (html only)
259
    ];
260
261
    /**
262
     * Class for read only interaction with FlexiBee.
263
     *
264
     * @param mixed $init default record id or initial data
265
     * @param array $options Connection settings override
266
     */
267
    public function __construct($init = null, $options = [])
268
    {
269
        $this->init = $init;
270
271
        parent::__construct();
272
        $this->setUp($options);
273
        $this->curlInit();
274
        if (!is_null($init)) {
275
            $this->processInit($init);
276
        }
277
    }
278
279
    /**
280
     * SetUp Object to be ready for connect
281
     *
282
     * @param array $options Object Options
283
     */
284
    public function setUp($options = [])
285
    {
286 View Code Duplication
        if (isset($options['company'])) {
1 ignored issue
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...
287
            $this->company = $options['company'];
288
        } else {
289
            if (is_null($this->company) && defined('FLEXIBEE_COMPANY')) {
290
                $this->company = constant('FLEXIBEE_COMPANY');
291
            }
292
        }
293 View Code Duplication
        if (isset($options['url'])) {
1 ignored issue
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...
294
            $this->url = $options['url'];
295
        } else {
296
            if (is_null($this->url) && defined('FLEXIBEE_URL')) {
297
                $this->url = constant('FLEXIBEE_URL');
298
            }
299
        }
300 View Code Duplication
        if (isset($options['user'])) {
1 ignored issue
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...
301
            $this->user = $options['user'];
302
        } else {
303
            if (is_null($this->user) && defined('FLEXIBEE_LOGIN')) {
304
                $this->user = constant('FLEXIBEE_LOGIN');
305
            }
306
        }
307 View Code Duplication
        if (isset($options['password'])) {
1 ignored issue
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...
308
            $this->password = $options['password'];
309
        } else {
310
            if (is_null($this->password) && defined('FLEXIBEE_PASSWORD')) {
311
                $this->password = constant('FLEXIBEE_PASSWORD');
312
            }
313
        }
314
        if (isset($options['evidence'])) {
315
            $this->setEvidence($options['evidence']);
316
        }
317
    }
318
319
    /**
320
     * Inicializace CURL
321
     */
322
    public function curlInit()
323
    {
324
        $this->curl = \curl_init(); // create curl resource
325
        curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); // return content as a string from curl_exec
326
        curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true); // follow redirects (compatibility for future changes in FlexiBee)
327
        curl_setopt($this->curl, CURLOPT_HTTPAUTH, true);       // HTTP authentication
328
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false); // FlexiBee by default uses Self-Signed certificates
329
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false);
330
        curl_setopt($this->curl, CURLOPT_VERBOSE, true); // For debugging
331
        curl_setopt($this->curl, CURLOPT_USERPWD,
332
            $this->user.':'.$this->password); // set username and password
333
    }
334
335
    /**
336
     * Zinicializuje objekt dle daných dat
337
     * 
338
     * @param mixed $init
339
     */
340
    public function processInit($init)
341
    {
342
        if (is_integer($init)) {
343
            $this->loadFromFlexiBee($init);
344
        } elseif (is_array($init)) {
345
            $this->takeData($init);
346
        } elseif (strstr($init, 'code:')) {
347
            $this->loadFromFlexiBee($init);
348
        }
349
    }
350
351
    /**
352
     * Nastaví Evidenci pro Komunikaci.
353
     *
354
     * @param string $evidence
355
     */
356
    public function setEvidence($evidence)
357
    {
358
        $this->evidence = $evidence;
359
    }
360
361
    /**
362
     * Vrací právě používanou evidenci pro komunikaci
363
     *
364
     * @return string
365
     */
366
    public function getEvidence()
367
    {
368
        return $this->evidence;
369
    }
370
371
    /**
372
     * Set used company.
373
     * Nastaví Firmu.
374
     *
375
     * @param string $company
376
     */
377
    public function setCompany($company)
378
    {
379
        $this->company = $company;
380
    }
381
382
    /**
383
     * Obtain company now used
384
     * Vrací právě používanou firmu
385
     *
386
     * @return string
387
     */
388
    public function getCompany()
389
    {
390
        return $this->company;
391
    }
392
393
    /**
394
     * Vrací název evidence použité v odpovědích z FlexiBee
395
     *
396
     * @return string
397
     */
398
    public function getResponseEvidence()
399
    {
400
        switch ($this->evidence) {
401
            case 'c':
402
                $evidence = 'companies';
403
                break;
404
            default:
405
                $evidence = $this->getEvidence();
406
                break;
407
        }
408
        return $evidence;
409
    }
410
411
    /**
412
     * Převede rekurzivně Objekt na pole.
413
     *
414
     * @param object|array $object
415
     *
416
     * @return array
417
     */
418
    public static function object2array($object)
419
    {
420
        $result = null;
421
        if (is_object($object)) {
422
            $objectData = get_object_vars($object);
423
            if (is_array($objectData) && count($objectData)) {
424
                $result = array_map('self::object2array', $objectData);
425
            }
426 View Code Duplication
        } else {
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...
427
            if (is_array($object)) {
428
                foreach ($object as $item => $value) {
429
                    $result[$item] = self::object2array($value);
430
                }
431
            } else {
432
                $result = $object;
433
            }
434
        }
435
436
        return $result;
437
    }
438
439
    /**
440
     * Převede rekurzivně v poli všechny objekty na jejich identifikátory.
441
     *
442
     * @param object|array $object
443
     *
444
     * @return array
445
     */
446
    public static function objectToID($object)
447
    {
448
        $result = null;
449
        if (is_object($object)) {
450
            $result = $object->__toString();
451 View Code Duplication
        } else {
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...
452
            if (is_array($object)) {
453
                foreach ($object as $item => $value) {
454
                    $result[$item] = self::objectToID($value);
455
                }
456
            } else { //String
457
                $result = $object;
458
            }
459
        }
460
461
        return $result;
462
    }
463
464
    /**
465
     * Return basic URL for used Evidence
466
     *
467
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Sestavování URL
468
     * @param string $urlSuffix
469
     */
470
    public function getEvidenceURL($urlSuffix = null)
471
    {
472
        if (is_null($urlSuffix)) {
473
            $urlSuffix = $this->evidence;
474
        } elseif ($urlSuffix[0] == ';') {
475
            $urlSuffix = $this->evidence.$urlSuffix;
476
        }
477
        return $this->url.$this->prefix.$this->company.'/'.$urlSuffix;
478
    }
479
480
    /**
481
     * Funkce, která provede I/O operaci a vyhodnotí výsledek.
482
     *
483
     * @param string $urlSuffix část URL za identifikátorem firmy.
484
     * @param string $method    HTTP/REST metoda
485
     * @param string $format    Requested format
486
     * @return array|boolean Výsledek operace
487
     */
488
    public function performRequest($urlSuffix = null, $method = 'GET',
489
                                   $format = null)
490
    {
491
        $this->rowCount = null;
492
        $url            = $this->getEvidenceURL($urlSuffix);
493
494
        $responseCode = $this->doCurlRequest($url, $method, $format);
0 ignored issues
show
Documentation introduced by
$method is of type string, but the function expects a object<FlexiPeeHP\strinf>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
495
496
        if (is_null($format)) {
497
            $format = $this->format;
498
        }
499
500
        switch ($responseCode) {
501
            case 200:
502
            case 201:
503
                // Parse response
504
                $responseDecoded = [];
505
506
                switch ($format) {
507
                    case 'json':
508
                        $responseDecoded = json_decode($this->lastCurlResponse,
509
                            true, 10);
510
                        if (($method == 'PUT') && isset($responseDecoded[$this->nameSpace][$this->resultField][0]['id'])) {
511
                            $this->lastInsertedID = $responseDecoded[$this->nameSpace][$this->resultField][0]['id'];
512
                            $this->setMyKey($this->lastInsertedID);
513
                        } else {
514
                            $this->lastInsertedID = null;
515
                            if (isset($responseDecoded[$this->nameSpace]['@rowCount'])) {
516
                                $this->rowCount = (int) $responseDecoded[$this->nameSpace]['@rowCount'];
517
                            }
518
                        }
519
                        $decodeError = json_last_error_msg();
520
                        if ($decodeError != 'No error') {
521
                            $this->addStatusMessage($decodeError, 'error');
522
                        }
523
                        break;
524
                    case 'xml':
525
                        if (strlen($this->lastCurlResponse)) {
526
                            $responseDecoded = self::xml2array($this->lastCurlResponse);
527
                        } else {
528
                            $responseDecoded = null;
529
                        }
530
                        break;
531
                }
532
533
534
                $response         = $this->lastResult = $this->unifyResponseFormat($responseDecoded);
535
536
                break;
537
538
            default: //Some goes wrong
539
                $this->lastCurlError = curl_error($this->curl);
540
                switch ($format) {
541
                    case 'json':
542
                        $response = preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/',
543
                            function ($match) {
544
                            return mb_convert_encoding(pack('H*', $match[1]),
545
                                'UTF-8', 'UCS-2BE');
546
                        }, $this->lastCurlResponse);
547
                        $response = (json_encode(json_decode($response, true, 10),
548
                                JSON_PRETTY_PRINT));
549
                        break;
550
                    case 'xml':
551
                        if (strlen($this->lastCurlResponse)) {
552
                            $response = self::xml2array($this->lastCurlResponse);
553
                        }
554
                        break;
555
                }
556
557
                if (is_array($response)) {
558
                    $result = urldecode(http_build_query($response));
0 ignored issues
show
Bug introduced by
The variable $response does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
559
                } elseif (strlen($response) && ($response != 'null')) {
560
                    $result = urldecode(http_build_query(self::object2array(current(json_decode($response)))));
561
                } else {
562
                    $result = null;
563
                }
564
565
                if ($response == 'null') {
566
                    if ($this->lastResponseCode == 200) {
567
                        $response = true;
568
                    } else {
569
                        $response = null;
570
                    }
571
                } else {
572
                    if (is_string($response)) {
573
                        $response = self::object2array(current(json_decode($response)));
574
                    }
575
                }
576
577
                if (is_array($response) && ($this->lastResponseCode == 400)) {
578
                    $this->logResult($response, $url);
579
                } else {
580
                    $this->addStatusMessage(sprintf('Error (HTTP %d): <pre>%s</pre> %s',
581
                            curl_getinfo($this->curl, CURLINFO_HTTP_CODE),
582
                            $result, $this->lastCurlError), 'error');
583
                    $this->addStatusMessage($url, 'info');
584
                    if (count($this->postFields)) {
585
                        if (is_array($result)) {
586
                            $this->addStatusMessage(urldecode(http_build_query($this->postFields)),
587
                                'debug');
588
                        } else {
589
                            $this->addStatusMessage(urldecode(http_build_query($this->getData())),
590
                                'debug');
591
                        }
592
                    }
593
                }
594
595
                break;
596
        }
597
        return $response;
598
    }
599
600
    /**
601
     * Vykonej HTTP požadavek
602
     *
603
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Sestavování URL
604
     * @param string $url    URL požadavku
605
     * @param strinf $method HTTP Method GET|POST|PUT|OPTIONS|DELETE
606
     * @param string $format požadovaný formát komunikace
607
     * @return int HTTP Response CODE
608
     */
609
    public function doCurlRequest($url, $method, $format = null)
610
    {
611
        if (is_null($format)) {
612
            $format = $this->format;
613
        }
614
        curl_setopt($this->curl, CURLOPT_URL, $url);
615
// Nastavení samotné operace
616
        curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, strtoupper($method));
617
//Vždy nastavíme byť i prázná postdata jako ochranu před chybou 411
618
        curl_setopt($this->curl, CURLOPT_POSTFIELDS, $this->postFields);
619
620
        $httpHeaders = $this->defaultHttpHeaders;
621
        switch ($format) {
622
            case 'json':
623
                $httpHeaders['Accept']       = 'application/json';
624
                $httpHeaders['Content-Type'] = 'application/json';
625
626
                break;
627
            case 'xml':
628
                $httpHeaders['Accept']       = 'application/xml';
629
                $httpHeaders['Content-Type'] = 'application/xml';
630
                break;
631
        }
632
633
        $httpHeadersFinal = [];
634
        foreach ($httpHeaders as $key => $value) {
635
            $httpHeadersFinal[] = $key.': '.$value;
636
        }
637
638
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, $httpHeadersFinal);
639
640
// Proveď samotnou operaci
641
        $this->lastCurlResponse = curl_exec($this->curl);
642
643
        $this->info = curl_getinfo($this->curl);
644
645
        $this->lastResponseCode = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
646
        return $this->lastResponseCode;
647
    }
648
649
    /**
650
     * Nastaví druh prováděné akce.
651
     *
652
     * @link https://demo.flexibee.eu/devdoc/actions Provádění akcí
653
     * @param string $action
654
     * @return boolean
655
     */
656
    public function setAction($action)
657
    {
658
        $result = false;
659
        if (is_null($this->actionsAvailable)) {
660
            $this->action = $action;
661
            $result       = true;
662
        } else {
663
            if (array_search($action, $this->actionsAvailable)) {
664
                $this->action = $action;
665
                $result       = true;
666
            }
667
        }
668
        return $result;
669
    }
670
671
    /**
672
     * Convert XML to array.
673
     *
674
     * @param string $xml
675
     *
676
     * @return array
677
     */
678
    public static function xml2array($xml)
679
    {
680
        $arr = [];
681
682
        if (is_string($xml)) {
683
            $xml = simplexml_load_string($xml);
684
        }
685
686
        foreach ($xml->children() as $r) {
687
            if (count($r->children()) == 0) {
688
                $arr[$r->getName()] = strval($r);
689
            } else {
690
                $arr[$r->getName()][] = self::xml2array($r);
691
            }
692
        }
693
694
        return $arr;
695
    }
696
697
    /**
698
     * Odpojení od FlexiBee.
699
     */
700
    public function disconnect()
701
    {
702
        if (is_resource($this->curl)) {
703
            curl_close($this->curl);
704
        }
705
        $this->curl = null;
706
    }
707
708
    public function __destruct()
709
    {
710
        $this->disconnect();
711
    }
712
713
    /**
714
     * Načte řádek dat z FlexiBee.
715
     *
716
     * @param int $recordID id požadovaného záznamu
717
     *
718
     * @return array
719
     */
720
    public function getFlexiRow($recordID)
721
    {
722
        $record   = null;
723
        $response = $this->performRequest($this->evidence.'/'.$recordID.'.json');
724
        if (isset($response[$this->evidence])) {
725
            $record = $response[$this->evidence][0];
726
        }
727
728
        return $record;
729
    }
730
731
    /**
732
     * Oddělí z pole podmínek ty jenž patří za ? v URL požadavku
733
     *
734
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Sestavování URL
735
     * @param array $conditions pole podmínek   - rendrují se do ()
736
     * @param array $urlParams  pole parametrů  - rendrují za ?
737
     */
738
    public function extractUrlParams(&$conditions, &$urlParams)
739
    {
740
        foreach ($this->urlParams as $urlParam) {
741
            if (isset($conditions[$urlParam])) {
742
                \Ease\Sand::divDataArray($conditions, $urlParams, $urlParam);
743
            }
744
        }
745
    }
746
747
    /**
748
     * Načte data z FlexiBee.
749
     *
750
     * @param string $suffix     dotaz
751
     * @param string|array $conditions Volitelný filtrovací výraz
752
     */
753
    public function getFlexiData($suffix = null, $conditions = null)
754
    {
755
        $urlParams = $this->defaultUrlParams;
756
        if (!is_null($conditions)) {
757
            if (is_array($conditions)) {
758
                $this->extractUrlParams($conditions, $urlParams);
759
                $conditions = $this->flexiUrl($conditions);
760
            }
761
762
            if (strlen($conditions) && ($conditions[0] != '/')) {
763
                $conditions = '/'.rawurlencode('('.($conditions).')');
764
            }
765
        } else {
766
            $conditions = '';
767
        }
768
        if (strlen($suffix)) {
769
            $transactions = $this->performRequest($this->evidence.$conditions.'.'.$this->format.'?'.$suffix.'&'.http_build_query($urlParams),
770
                'GET');
771
        } else {
772
            $transactions = $this->performRequest($this->evidence.$conditions.'.'.$this->format.'?'.http_build_query($urlParams),
773
                'GET');
774
        }
775
        if (isset($transactions[$this->evidence])) {
776
            $result = $transactions[$this->evidence];
777
        } else {
778
            $result = $transactions;
779
        }
780
781
        return $result;
782
    }
783
784
    /**
785
     * Načte záznam z FlexiBee.
786
     *
787
     * @param int $id ID záznamu
788
     *
789
     * @return int počet načtených položek
790
     */
791 View Code Duplication
    public function loadFromFlexiBee($id = null)
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...
792
    {
793
        $data = [];
794
        if (is_null($id)) {
795
            $id = $this->getMyKey();
796
        }
797
798
        $flexidata = $this->getFlexiData(null, '/'.$id);
799
        if (count($flexidata) == 1) {
800
            $data = current($flexidata);
801
        }
802
        return $this->takeData($data);
803
    }
804
805
    /**
806
     * Převede data do Json formátu pro FlexiBee.
807
     *
808
     * @param array $data
809
     *
810
     * @return string
811
     */
812
    public function jsonizeData($data)
813
    {
814
        $jsonize = [
815
            $this->nameSpace => [
816
                '@version' => $this->protoVersion,
817
                $this->evidence => $this->objectToID($data),
818
            ],
819
        ];
820
821
        if (!is_null($this->action)) {
822
            $jsonize[$this->nameSpace][$this->evidence.'@action'] = $this->action;
823
            $this->action                                         = null;
824
        }
825
826
        return json_encode($jsonize);
827
    }
828
829
    /**
830
     * Test if given record ID exists in FlexiBee.
831
     *
832
     * @param string|int $identifer
833
     */
834
    public function idExists($identifer = null)
835
    {
836
        if (is_null($identifer)) {
837
            $identifer = $this->getMyKey();
838
        }
839
        $flexiData = $this->getFlexiData(
840
            'detail=custom:'.$this->getmyKeyColumn(), $identifer);
841
842
        return $flexiData;
843
    }
844
845
    /**
846
     * Test if given record exists in FlexiBee.
847
     *
848
     * @param array $data
849
     * @return boolean Record presence status
850
     */
851
    public function recordExists($data = null)
852
    {
853
        $found = null;
0 ignored issues
show
Unused Code introduced by
$found is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
854
        if (is_null($data)) {
855
            $data = $this->getData();
856
        }
857
858
        $res = $this->getColumnsFromFlexibee([$this->myKeyColumn],
859
            self::flexiUrl($data));
0 ignored issues
show
Documentation introduced by
self::flexiUrl($data) is of type string, but the function expects a array|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
860
861
        if (!count($res) || (isset($res['success']) && ($res['success'] == 'false'))
862
            || !count($res[0])) {
863
            $found = false;
864
        } else {
865
            $found = true;
866
        }
867
        return $found;
868
    }
869
870
    /**
871
     * Vrací z FlexiBee sloupečky podle podmínek.
872
     *
873
     * @param array|int|string $conditions pole podmínek nebo ID záznamu
874
     * @param string           $indexBy    klice vysledku naplnit hodnotou ze
875
     *                                     sloupečku
876
     * @return array
877
     */
878 View Code Duplication
    public function getAllFromFlexibee($conditions = null, $indexBy = null)
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...
879
    {
880
        if (is_int($conditions)) {
881
            $conditions = [$this->getmyKeyColumn() => $conditions];
882
        }
883
884
        $flexiData = $this->getFlexiData('', $conditions);
885
886
        if (!is_null($indexBy)) {
887
            $flexiData = $this->reindexArrayBy($flexiData);
888
        }
889
890
        return $flexiData;
891
    }
892
893
    /**
894
     * Vrací z FlexiBee sloupečky podle podmínek.
895
     *
896
     * @param string[] $columnsList seznam položek
897
     * @param array    $conditions  pole podmínek nebo ID záznamu
898
     * @param string   $indexBy     Sloupeček podle kterého indexovat záznamy
899
     *
900
     * @return array
901
     */
902
    public function getColumnsFromFlexibee($columnsList, $conditions = null,
903
                                           $indexBy = null)
904
    {
905
        $detail = 'full';
906
907
        if (is_int($conditions)) {
908
            $conditions = [$this->getmyKeyColumn() => $conditions];
909
        }
910
911
        if ($columnsList != '*') {
912
            if (is_array($columnsList)) {
913
            $columns = implode(',', array_unique($columnsList));
914
        } else {
915
            $columns = $columnsList;
916
        }
917
            $detail = 'custom:'.$columns;
918
        }
919
920
        $flexiData = $this->getFlexiData('detail='.$detail, $conditions);
921
922
        if (!is_null($indexBy)) {
923
            $flexiData = $this->reindexArrayBy($flexiData, $indexBy);
924
        }
925
926
        return $flexiData;
927
    }
928
929
    /**
930
     * Vrací kód záznamu.
931
     *
932
     * @param mixed $data
933
     *
934
     * @return string
935
     */
936
    public function getKod($data = null, $unique = true)
937
    {
938
        $kod = null;
939
940
        if (is_null($data)) {
941
            $data = $this->getData();
942
        }
943
944
        if (is_string($data)) {
945
            $data = [$this->nameColumn => $data];
946
        }
947
948
        if (isset($data['kod'])) {
949
            $kod = $data['kod'];
950
        } else {
951
            if (isset($data[$this->nameColumn])) {
952
                $kod = preg_replace('/[^a-zA-Z0-9]/', '',
953
                    \Ease\Sand::rip($data[$this->nameColumn]));
954
            } else {
955
                if (isset($data[$this->myKeyColumn])) {
956
                    $kod = \Ease\Sand::rip($data[$this->myKeyColumn]);
957
                }
958
            }
959
        }
960
961
        if (!strlen($kod)) {
962
            $kod = 'NOTSET';
963
        }
964
965
        if (strlen($kod) > 18) {
966
            $kodfinal = strtoupper(substr($kod, 0, 18));
967
        } else {
968
            $kodfinal = strtoupper($kod);
969
        }
970
971
        if ($unique) {
972
            $counter = 0;
973
            if (count($this->codes)) {
974
                foreach ($this->codes as $codesearch => $keystring) {
975
                    if (strstr($codesearch, $kodfinal)) {
976
                        ++$counter;
977
                    }
978
                }
979
            }
980
            if ($counter) {
981
                $kodfinal = $kodfinal.$counter;
982
            }
983
984
            $this->codes[$kodfinal] = $kod;
985
        }
986
987
        return $kodfinal;
988
    }
989
990
    /**
991
     * Write Operation Result.
992
     *
993
     * @param array  $resultData
994
     * @param string $url        URL
995
     * @return boolean Log save success
996
     */
997
    public function logResult($resultData = null, $url = null)
998
    {
999
        $logResult = false;
1000
        if (isset($resultData['success']) && ($resultData['success'] == 'false')) {
1001
            if (isset($resultData['message'])) {
1002
                $this->addStatusMessage($resultData['message'], 'warning');
1003
            }
1004
            $this->addStatusMessage('Error '.$this->lastResponseCode.': '.urldecode($url),
1005
                'warning');
1006
            unset($url);
1007
        }
1008
        if (is_null($resultData)) {
1009
            $resultData = $this->lastResult;
1010
        }
1011
        if (isset($url)) {
1012
            $this->logger->addStatusMessage(urldecode($url));
1013
        }
1014
1015
        if (isset($resultData['results'])) {
1016
            $status = null;
0 ignored issues
show
Unused Code introduced by
$status is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1017
            if ($resultData['success'] == 'false') {
1018
                $status = 'error';
1019
            } else {
1020
                $status = 'success';
1021
            }
1022
            foreach ($resultData['results'] as $result) {
1023
                if (isset($result['request-id'])) {
1024
                    $rid = $result['request-id'];
1025
                } else {
1026
                    $rid = '';
1027
                }
1028
                if (isset($result['errors'])) {
1029
                    foreach ($result['errors'] as $error) {
1030
                        $message = $error['message'];
1031
                        if (isset($error['for'])) {
1032
                            $message .= ' for: '.$error['for'];
1033
                        }
1034
                        if (isset($error['value'])) {
1035
                            $message .= ' value:'.$error['value'];
1036
                        }
1037
                        if (isset($error['code'])) {
1038
                            $message .= ' code:'.$error['code'];
1039
                        }
1040
                        $this->addStatusMessage($rid.': '.$message, $status);
1041
                    }
1042
                }
1043
            }
1044
        }
1045
1046
        if (is_object($this->logger)) {
1047
            $logResult = $this->logger->flush(get_class($this));
1048
        }
1049
        return $logResult;
1050
    }
1051
1052
    /**
1053
     * Save RAW Curl Request & Response to files in Temp directory
1054
     */
1055
    public function saveDebugFiles()
1056
    {
1057
        $tmpdir = sys_get_temp_dir();
1058
        file_put_contents($tmpdir.'/request-'.$this->evidence.'-'.microtime().'.'.$this->format,
1059
            $this->postFields);
1060
        file_put_contents($tmpdir.'/response-'.$this->evidence.'-'.microtime().'.'.$this->format,
1061
            $this->lastCurlResponse);
1062
    }
1063
1064
    /**
1065
     * Připraví data pro odeslání do FlexiBee
1066
     * 
1067
     * @param string $data
1068
     */
1069
    public function setPostFields($data)
1070
    {
1071
        $this->postFields = $data;
0 ignored issues
show
Documentation Bug introduced by
It seems like $data of type string is incompatible with the declared type array of property $postFields.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1072
    }
1073
1074
    /**
1075
     * Generuje fragment url pro filtrování.
1076
     *
1077
     * @see https://www.flexibee.eu/api/dokumentace/ref/filters
1078
     *
1079
     * @param array  $data
1080
     * @param string $joiner default and/or
1081
     * @param string $defop  default operator
1082
     *
1083
     * @return string
1084
     */
1085
    public static function flexiUrl(array $data, $joiner = 'and', $defop = 'eq')
1086
    {
1087
        $flexiUrl = '';
0 ignored issues
show
Unused Code introduced by
$flexiUrl is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1088
        $parts    = [];
1089
1090
        foreach ($data as $column => $value) {
1091
            if (is_integer($data[$column]) || is_float($data[$column])) {
1092
                $parts[$column] = $column.' eq \''.$data[$column].'\'';
1093
            } elseif (is_bool($data[$column])) {
1094
                $parts[$column] = $data[$column] ? $column.' eq true' : $column.' eq false';
1095
            } elseif (is_null($data[$column])) {
1096
                $parts[$column] = $column." is null";
1097
            } elseif ($value == '!null') {
1098
                $parts[$column] = $column." is not null";
1099
            } else {
1100
                $parts[$column] = $column." $defop '".$data[$column]."'";
1101
            }
1102
        }
1103
1104
        $flexiUrl = implode(' '.$joiner.' ', $parts);
1105
1106
        return $flexiUrl;
1107
    }
1108
1109
    /**
1110
     * Vrací identifikátor objektu code: nebo id:
1111
     *
1112
     * @link https://demo.flexibee.eu/devdoc/identifiers Identifikátory záznamů
1113
     * @return string indentifikátor záznamu reprezentovaného objektem
1114
     */
1115
    public function __toString()
1116
    {
1117
        $myCode = $this->getDataValue('kod');
1118
        if ($myCode) {
1119
            $id = 'code:'.$myCode;
1120
        } else {
1121
            $id = $this->getDataValue('id');
1122
            if (is_null($id)) {
1123
                $this->addToLog('Object Data does not contain code: or id: cannot match with statement!',
1124
                    'warning');
1125
            }
1126
        }
1127
        return $id;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $id; (object|integer|double|string|array|boolean|null) is incompatible with the return type of the parent method Ease\Sand::__toString of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1128
    }
1129
1130
    /**
1131
     * Gives you FlexiPeeHP class name for Given Evidence
1132
     *
1133
     * @param string $evidence
1134
     * @return string Class name
1135
     */
1136
    static public function evidenceToClassName($evidence)
0 ignored issues
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
1137
    {
1138
        return str_replace(' ', '', ucwords(str_replace('-', ' ', $evidence)));
1139
    }
1140
1141
    /**
1142
     * Vrací hodnotu daného externího ID
1143
     *
1144
     * @param string $want Which ? If empty,you obtain the first one.
1145
     * @return string
1146
     */
1147
    public function getExternalID($want = null)
1148
    {
1149
        $extid = null;
1150
        $ids   = $this->getDataValue('external-ids');
1151
        if (is_null($want)) {
1152
            if (count($ids)) {
1153
                $extid = current($ids);
1154
            }
1155
        } else {
1156
            if (!is_null($ids)) {
1157
                foreach ($ids as $id) {
0 ignored issues
show
Bug introduced by
The expression $ids of type object|integer|double|string|array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1158
                    if (strstr($id, 'ext:'.$want)) {
1159
                        $extid = str_replace('ext:'.$want.':', '', $id);
1160
                    }
1161
                }
1162
            }
1163
        }
1164
        return $extid;
1165
    }
1166
1167
    /**
1168
     * Obtain actual GlobalVersion
1169
     * Vrací aktuální globální verzi změn
1170
     *
1171
     * @link https://www.flexibee.eu/api/dokumentace/ref/changes-api#globalVersion Globální Verze
1172
     * @return type
1173
     */
1174
    public function getGlobalVersion()
1175
    {
1176
        $globalVersion = null;
1177
        if (!count($this->lastResult) || !isset($this->lastResult['@globalVersion'])) {
1178
            $this->getFlexiData(null,
1179
                ['add-global-version' => 'true', 'limit' => 1]);
1180
        }
1181
1182
        if (isset($this->lastResult['@globalVersion'])) {
1183
            $globalVersion = intval($this->lastResult['@globalVersion']);
1184
        }
1185
1186
        return $globalVersion;
1187
    }
1188
1189
    /**
1190
     * Return the same response format for one and multiplete results
1191
     * 
1192
     * @param array $responseRaw
1193
     * @return array
1194
     */
1195
    public function unifyResponseFormat($responseRaw)
1196
    {
1197
        $response = null;
1198
        $evidence = $this->getResponseEvidence();
1199
        if (is_array($responseRaw)) {
1200
            // Get response body root automatically
1201
            if (array_key_exists($this->nameSpace, $responseRaw)) { //Unifi response format
1202
                $responseBody = $responseRaw[$this->nameSpace];
1203
                if (array_key_exists($evidence, $responseBody)) {
1204
                    $evidenceContent = $responseBody[$evidence];
1205
                    if (array_key_exists(0, $evidenceContent)) {
1206
                        $response[$evidence] = $evidenceContent; //Multiplete Results
1207
                    } else {
1208
                        $response[$evidence][0] = $evidenceContent; //One result
1209
                    }
1210
                } else {
1211
                    $response = $responseBody;
1212
                }
1213
            } else {
1214
                $response = $responseRaw;
1215
            }
1216
        }
1217
        return $response;
1218
    }
1219
1220
    /**
1221
     * Obtain structure for given (or default) evidence
1222
     *
1223
     * @param string $evidence
1224
     * @return array Evidence structure
1225
     */
1226
    public function getColumnsInfo($evidence = null)
1227
    {
1228
        $columnsInfo = null;
1229
        if (is_null($evidence)) {
1230
            $evidence = $this->getEvidence();
1231
        }
1232
        $propsName = lcfirst(\FlexiPeeHP\FlexiBeeRO::evidenceToClassName($evidence));
1233
        if (isset(\FlexiPeeHP\Structure::$$propsName)) {
1234
            $columnsInfo = \FlexiPeeHP\Structure::$$propsName;
1235
        }
1236
        return $columnsInfo;
1237
    }
1238
1239
}
1240