Test Failed
Push — master ( 354000...89c269 )
by Vítězslav
11:24
created

FlexiBeeRO   D

Complexity

Total Complexity 271

Size/Duplication

Total Lines 1806
Duplicated Lines 3.93 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
dl 71
loc 1806
rs 4
c 0
b 0
f 0
wmc 271
lcom 1
cbo 6

63 Methods

Rating   Name   Duplication   Size   Complexity  
A curlInit() 0 12 1
A __construct() 0 11 2
A saveResponseToFile() 0 7 2
A getVazby() 0 10 2
C getFlexiBeeURL() 0 13 9
A setUp() 0 16 3
B setupProperty() 0 10 5
B processInit() 0 13 5
C setPrefix() 0 21 11
B setFormat() 0 15 6
A setEvidence() 0 20 3
A getEvidence() 0 4 1
A setCompany() 0 4 1
A getCompany() 0 4 1
A getResponseEvidence() 0 15 3
B object2array() 9 20 6
A objectToID() 9 17 4
A getEvidenceURL() 0 9 3
A updateApiURL() 0 9 2
A performRequest() 0 16 3
B rawResponseToArray() 0 26 6
C parseResponse() 0 38 11
A parseError() 0 9 2
C doCurlRequest() 0 50 9
A setAction() 0 10 2
A xml2array() 0 18 4
A disconnect() 0 7 2
A __destruct() 0 4 1
A getFlexiRow() 0 10 2
A extractUrlParams() 0 8 3
C getFlexiData() 0 40 11
B loadFromFlexiBee() 0 15 5
A jsonizeData() 7 20 3
A idExists() 0 10 2
B recordExists() 0 18 6
A getAllFromFlexibee() 0 14 3
D getColumnsFromFlexibee() 0 36 10
D getKod() 0 53 13
C logResult() 0 49 15
A saveDebugFiles() 0 9 1
A setPostFields() 0 4 1
C flexiUrl() 0 32 11
B getRecordID() 0 14 5
A __toString() 0 4 1
A evidenceToClassName() 0 4 1
B getExternalID() 0 19 7
A getGlobalVersion() 0 14 4
A getResponseFormat() 0 9 2
B unifyResponseFormat() 0 25 6
A getColumnsInfo() 12 12 3
A getActionsInfo() 12 12 3
A getRelationsInfo() 0 12 3
A getEvidenceInfo() 11 11 3
A getEvidenceName() 11 11 3
B performAction() 0 35 6
A setMyKey() 0 6 1
A ignore404() 0 7 2
A sendByMail() 0 8 1
A sendUnsent() 0 5 1
A flexiDateToDateTime() 0 4 1
A getInFormat() 0 11 4
A downloadInFormat() 0 12 4
C error500Reporter() 0 66 14

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like FlexiBeeRO 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 FlexiBeeRO, and based on these observations, apply Extract Interface, too.

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-2017 Spoje.Net
7
 */
8
9
namespace FlexiPeeHP;
10
11
/**
12
 * Základní třída pro čtení z FlexiBee
13
 *
14
 * @url https://demo.flexibee.eu/devdoc/
15
 */
16
class FlexiBeeRO extends \Ease\Brick
17
{
18
    /**
19
     * Version of FlexiPeeHP library
20
     *
21
     * @var string
22
     */
23
    public static $libVersion = '1.6.4.2';
24
25
    /**
26
     * Základní namespace pro komunikaci s FlexiBee.
27
     * Basic namespace for communication with FlexiBee
28
     *
29
     * @var string Jmený prostor datového bloku odpovědi
30
     */
31
    public $nameSpace = 'winstrom';
32
33
    /**
34
     * URL of object data in FlexiBee
35
     * @var string url
36
     */
37
    public $apiURL = null;
38
39
    /**
40
     * Datový blok v poli odpovědi.
41
     * Data block in response field.
42
     *
43
     * @var string
44
     */
45
    public $resultField = 'results';
46
47
    /**
48
     * Verze protokolu použitého pro komunikaci.
49
     * Communication protocol version used.
50
     *
51
     * @var string Verze použitého API
52
     */
53
    public $protoVersion = '1.0';
54
55
    /**
56
     * Evidence užitá objektem.
57
     * Evidence used by object
58
     *
59
     * @link https://demo.flexibee.eu/c/demo/evidence-list Přehled evidencí
60
     * @var string
61
     */
62
    public $evidence = null;
63
64
    /**
65
     * Výchozí formát pro komunikaci.
66
     * Default communication format.
67
     *
68
     * @link https://www.flexibee.eu/api/dokumentace/ref/format-types Přehled možných formátů
69
     *
70
     * @var string json|xml|...
71
     */
72
    public $format = 'json';
73
74
    /**
75
     * formát příchozí odpovědi
76
     * response format
77
     *
78
     * @link https://www.flexibee.eu/api/dokumentace/ref/format-types Přehled možných formátů
79
     *
80
     * @var string json|xml|...
81
     */
82
    public $responseFormat = 'json';
83
84
    /**
85
     * Curl Handle.
86
     *
87
     * @var resource
88
     */
89
    public $curl = null;
90
91
    /**
92
     * @link https://demo.flexibee.eu/devdoc/company-identifier Identifikátor firmy
93
     * @var string
94
     */
95
    public $company = null;
96
97
    /**
98
     * Server[:port]
99
     * @var string
100
     */
101
    public $url = null;
102
103
    /**
104
     * REST API Username
105
     * @var string
106
     */
107
    public $user = null;
108
109
    /**
110
     * REST API Password
111
     * @var string
112
     */
113
    public $password = null;
114
115
    /**
116
     * @var array Pole HTTP hlaviček odesílaných s každým požadavkem
117
     */
118
    public $defaultHttpHeaders = ['User-Agent' => 'FlexiPeeHP'];
119
120
    /**
121
     * Default additional request url parameters after question mark
122
     *
123
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls   Common params
124
     * @link https://www.flexibee.eu/api/dokumentace/ref/paging Paging params
125
     * @var array
126
     */
127
    public $defaultUrlParams = ['limit' => 0];
128
129
    /**
130
     * Identifikační řetězec.
131
     *
132
     * @var string
133
     */
134
    public $init = null;
135
136
    /**
137
     * Sloupeček s názvem.
138
     *
139
     * @var string
140
     */
141
    public $nameColumn = 'nazev';
142
143
    /**
144
     * Sloupeček obsahující datum vložení záznamu do shopu.
145
     *
146
     * @var string
147
     */
148
    public $myCreateColumn = 'false';
149
150
    /**
151
     * Slopecek obsahujici datum poslení modifikace záznamu do shopu.
152
     *
153
     * @var string
154
     */
155
    public $myLastModifiedColumn = 'lastUpdate';
156
157
    /**
158
     * Klíčový idendifikátor záznamu.
159
     *
160
     * @var string
161
     */
162
    public $fbKeyColumn = 'id';
163
164
    /**
165
     * Informace o posledním HTTP requestu.
166
     *
167
     * @var *
168
     */
169
    public $curlInfo;
170
171
    /**
172
     * Informace o poslední HTTP chybě.
173
     *
174
     * @var string
175
     */
176
    public $lastCurlError = null;
177
178
    /**
179
     * Used codes storage.
180
     *
181
     * @var array
182
     */
183
    public $codes = null;
184
185
    /**
186
     * Last Inserted ID.
187
     *
188
     * @var int
189
     */
190
    public $lastInsertedID = null;
191
192
    /**
193
     * Default Line Prefix.
194
     *
195
     * @var string
196
     */
197
    public $prefix = '/c/';
198
199
    /**
200
     * Raw Content of last curl response
201
     *
202
     * @var string
203
     */
204
    public $lastCurlResponse;
205
206
    /**
207
     * HTTP Response code of last request
208
     *
209
     * @var int
210
     */
211
    public $lastResponseCode = null;
212
213
    /**
214
     * Body data  for next curl POST operation
215
     *
216
     * @var string
217
     */
218
    protected $postFields = null;
219
220
    /**
221
     * Last operation result data or message(s)
222
     *
223
     * @var array
224
     */
225
    public $lastResult = null;
226
227
    /**
228
     * Nuber from  @rowCount
229
     * @var int
230
     */
231
    public $rowCount = null;
232
233
    /**
234
     * @link https://www.flexibee.eu/api/dokumentace/ref/zamykani-odemykani/
235
     * @var string filter query
236
     */
237
    public $filter;
238
239
    /**
240
     * @link https://demo.flexibee.eu/devdoc/actions Provádění akcí
241
     * @var string
242
     */
243
    protected $action;
244
245
    /**
246
     * Pole akcí které podporuje ta která evidence
247
     * @link https://demo.flexibee.eu/c/demo/faktura-vydana/actions.json Např. Akce faktury
248
     * @var array
249
     */
250
    public $actionsAvailable = null;
251
252
    /**
253
     * Parmetry pro URL
254
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Všechny podporované parametry
255
     * @var array
256
     */
257
    public $urlParams = [
258
        'idUcetniObdobi',
259
        'dry-run',
260
        'fail-on-warning',
261
        'report-name',
262
        'report-lang',
263
        'report-sign',
264
        'detail', //See: https://www.flexibee.eu/api/dokumentace/ref/detail-levels
265
        'mode',
266
        'limit',
267
        'start',
268
        'order',
269
        'sort',
270
        'add-row-count',
271
        'relations',
272
        'includes',
273
        'use-ext-id',
274
        'use-internal-id',
275
        'stitky-as-ids',
276
        'only-ext-ids',
277
        'no-ext-ids',
278
        'no-ids',
279
        'code-as-id',
280
        'no-http-errors',
281
        'export-settings',
282
        'as-gui',
283
        'code-in-response',
284
        'add-global-version',
285
        'encoding',
286
        'delimeter',
287
        'format',
288
        'auth',
289
        'skupina-stitku',
290
        'dir',
291
        'relations',
292
        'relations',
293
        'xpath', // See: https://www.flexibee.eu/api/dokumentace/ref/xpath/
294
        'dry-run', // See: https://www.flexibee.eu/api/dokumentace/ref/dry-run/
295
        'inDesktopApp' // Note: Undocumented function (html only)
296
    ];
297
298
    /**
299
     * Save 404 results to log ?
300
     * @var boolean
301
     */
302
    protected $ignoreNotFound = false;
303
304
    /**
305
     * Array of errors caused by last request
306
     * @var array
307
     */
308
    private $errors = [];
309
310
    /**
311
     * List of Error500 reports sent
312
     * @var array
313
     */
314
    private $reports = [];
315
316
    /**
317
     * Send Error500 Report to
318
     * @var string email address
319
     */
320
    public $reportRecipient = '[email protected]';
321
322
    /**
323
     * Class for read only interaction with FlexiBee.
324
     *
325
     * @param mixed $init default record id or initial data
326
     * @param array $options Connection settings override
327
     */
328
    public function __construct($init = null, $options = [])
329
    {
330
        $this->init = $init;
331
332
        parent::__construct();
333
        $this->setUp($options);
334
        $this->curlInit();
335
        if (!empty($init)) {
336
            $this->processInit($init);
337
        }
338
    }
339
340
    /**
341
     * SetUp Object to be ready for connect
342
     *
343
     * @param array $options Object Options (company,url,user,password,evidence,
344
     *                                       prefix,defaultUrlParams,debug)
345
     */
346
    public function setUp($options = [])
347
    {
348
        $this->setupProperty($options, 'company', 'FLEXIBEE_COMPANY');
349
        $this->setupProperty($options, 'url', 'FLEXIBEE_URL');
350
        $this->setupProperty($options, 'user', 'FLEXIBEE_LOGIN');
351
        $this->setupProperty($options, 'password', 'FLEXIBEE_PASSWORD');
352
        if (isset($options['evidence'])) {
353
            $this->setEvidence($options['evidence']);
354
        }
355
        $this->setupProperty($options, 'defaultUrlParams');
356
        if (isset($options['prefix'])) {
357
            $this->setPrefix($options['prefix']);
358
        }
359
        $this->setupProperty($options, 'debug');
360
        $this->updateApiURL();
361
    }
362
363
    /**
364
     * Set up one of properties
365
     *
366
     * @param array  $options  array of given properties
367
     * @param string $name     name of property to process
368
     * @param string $constant load default property value from constant
369
     */
370
    public function setupProperty($options, $name, $constant = null)
371
    {
372
        if (isset($options[$name])) {
373
            $this->$name = $options[$name];
374
        } else {
375
            if (is_null($this->$name) && !empty($constant) && defined($constant)) {
376
                $this->$name = constant($constant);
377
            }
378
        }
379
    }
380
381
    /**
382
     * Inicializace CURL
383
     */
384
    public function curlInit()
385
    {
386
        $this->curl = \curl_init(); // create curl resource
387
        curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); // return content as a string from curl_exec
388
        curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true); // follow redirects (compatibility for future changes in FlexiBee)
389
        curl_setopt($this->curl, CURLOPT_HTTPAUTH, true);       // HTTP authentication
390
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false); // FlexiBee by default uses Self-Signed certificates
391
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false);
392
        curl_setopt($this->curl, CURLOPT_VERBOSE, ($this->debug === true)); // For debugging
393
        curl_setopt($this->curl, CURLOPT_USERPWD,
394
            $this->user.':'.$this->password); // set username and password
395
    }
396
397
    /**
398
     * Zinicializuje objekt dle daných dat. Možné hodnoty:
399
     *
400
     *  * 234                              - interní číslo záznamu k načtení
401
     *  * code:LOPATA                      - kód záznamu
402
     *  * BAGR                             - kód záznamu ka načtení
403
     *  * ['id'=>24,'nazev'=>'hoblík']     - pole hodnot k předvyplnění
404
     *  * 743.json?relations=adresa,vazby  - část url s parametry k načtení
405
     *
406
     * @param mixed $init číslo/"(code:)kód"/(část)URI záznamu k načtení | pole hodnot k předvyplnění
407
     */
408
    public function processInit($init)
409
    {
410
        if (is_integer($init)) {
411
            $this->loadFromFlexiBee($init);
412
        } elseif (is_array($init)) {
413
            $this->takeData($init);
414
        } elseif (preg_match('/\.(json|xml|csv)/', $init)) {
415
            $this->takeData($this->getFlexiData((($init[0] != '/') ? $this->getEvidenceURL().'/'
416
                            : '').$init));
417
        } else {
418
            $this->loadFromFlexiBee('code:'.str_replace('code:', '', $init));
419
        }
420
    }
421
422
    /**
423
     * Set URL prefix
424
     *
425
     * @param string $prefix
426
     */
427
    public function setPrefix($prefix)
428
    {
429
        switch ($prefix) {
430
            case 'a': //Access
431
            case 'c': //Company
432
            case 'u': //User
433
            case 'g': //License Groups
434
            case 'admin':
435
            case 'status':
436
            case 'login-logout':
437
                $this->prefix = '/'.$prefix.'/';
438
                break;
439
            case null:
440
            case '':
441
            case '/':
442
                $this->prefix = '';
443
                break;
444
            default:
445
                throw new \Exception(sprintf('Unknown prefix %s', $prefix));
446
        }
447
    }
448
449
    /**
450
     * Set communication format.
451
     * One of html|xml|json|csv|dbf|xls|isdoc|isdocx|edi|pdf|pdf|vcf|ical
452
     *
453
     * @param string $format
454
     * @return boolen format is availble
455
     */
456
    public function setFormat($format)
457
    {
458
        $result = true;
459
        if (($this->debug === true) && !empty($this->evidence) && isset(Formats::$$this->evidence)) {
460
            if (array_key_exists($format, array_flip(Formats::$$this->evidence))
461
                === false) {
462
                $result = false;
463
            }
464
        }
465
        if ($result === true) {
466
            $this->format = $format;
467
            $this->updateApiURL();
468
        }
469
        return $result;
470
    }
471
472
    /**
473
     * Nastaví Evidenci pro Komunikaci.
474
     * Set evidence for communication
475
     *
476
     * @param string $evidence evidence pathName to use
477
     * @return boolean evidence switching status
478
     */
479
    public function setEvidence($evidence)
480
    {
481
        switch ($this->prefix) {
482
            case '/c/':
483
                if (array_key_exists($evidence, EvidenceList::$name)) {
484
                    $this->evidence = $evidence;
485
                    $result         = true;
486
                } else {
487
                    throw new \Exception(sprintf('Try to set unsupported evidence %s',
488
                        $evidence));
489
                }
490
                break;
491
            default:
492
                $this->evidence = $evidence;
493
                $result         = true;
494
                break;
495
        }
496
        $this->updateApiURL();
497
        return $result;
498
    }
499
500
    /**
501
     * Vrací právě používanou evidenci pro komunikaci
502
     * Obtain current used evidence
503
     *
504
     * @return string
505
     */
506
    public function getEvidence()
507
    {
508
        return $this->evidence;
509
    }
510
511
    /**
512
     * Set used company.
513
     * Nastaví Firmu.
514
     *
515
     * @param string $company
516
     */
517
    public function setCompany($company)
518
    {
519
        $this->company = $company;
520
    }
521
522
    /**
523
     * Obtain company now used
524
     * Vrací právě používanou firmu
525
     *
526
     * @return string
527
     */
528
    public function getCompany()
529
    {
530
        return $this->company;
531
    }
532
533
    /**
534
     * Vrací název evidence použité v odpovědích z FlexiBee
535
     *
536
     * @return string
537
     */
538
    public function getResponseEvidence()
539
    {
540
        switch ($this->evidence) {
541
            case 'c':
542
                $evidence = 'company';
543
                break;
544
            case 'evidence-list':
545
                $evidence = 'evidence';
546
                break;
547
            default:
548
                $evidence = $this->getEvidence();
549
                break;
550
        }
551
        return $evidence;
552
    }
553
554
    /**
555
     * Převede rekurzivně Objekt na pole.
556
     *
557
     * @param object|array $object
558
     *
559
     * @return array
560
     */
561
    public static function object2array($object)
562
    {
563
        $result = null;
564
        if (is_object($object)) {
565
            $objectData = get_object_vars($object);
566
            if (is_array($objectData) && count($objectData)) {
567
                $result = array_map('self::object2array', $objectData);
568
            }
569 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...
570
            if (is_array($object)) {
571
                foreach ($object as $item => $value) {
572
                    $result[$item] = self::object2array($value);
573
                }
574
            } else {
575
                $result = $object;
576
            }
577
        }
578
579
        return $result;
580
    }
581
582
    /**
583
     * Převede rekurzivně v poli všechny objekty na jejich identifikátory.
584
     *
585
     * @param object|array $object
586
     *
587
     * @return array
588
     */
589
    public static function objectToID($object)
590
    {
591
        $result = null;
592
        if (is_object($object)) {
593
            $result = $object->__toString();
594 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...
595
            if (is_array($object)) {
596
                foreach ($object as $item => $value) {
597
                    $result[$item] = self::objectToID($value);
598
                }
599
            } else { //String
600
                $result = $object;
601
            }
602
        }
603
604
        return $result;
605
    }
606
607
    /**
608
     * Return basic URL for used Evidence
609
     *
610
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Sestavování URL
611
     * @param string $urlSuffix
612
     */
613
    public function getEvidenceURL($urlSuffix = null)
614
    {
615
        if (is_null($urlSuffix)) {
616
            $urlSuffix = $this->getEvidence();
617
        } elseif ($urlSuffix[0] == ';') {
618
            $urlSuffix = $this->getEvidence().$urlSuffix;
619
        }
620
        return $this->url.$this->prefix.$this->company.'/'.$urlSuffix;
621
    }
622
623
    /**
624
     * Update $this->apiURL
625
     */
626
    public function updateApiURL()
627
    {
628
        $this->apiURL = $this->getEvidenceURL();
629
        $id           = $this->__toString();
630
        if (!empty($id)) {
631
            $this->apiURL .= '/'.urlencode($id);
632
        }
633
        $this->apiURL .= '.'.$this->format;
634
    }
635
636
    /**
637
     * Funkce, která provede I/O operaci a vyhodnotí výsledek.
638
     *
639
     * @param string $urlSuffix část URL za identifikátorem firmy.
640
     * @param string $method    HTTP/REST metoda
641
     * @param string $format    Requested format
642
     * @return array|boolean Výsledek operace
643
     */
644
    public function performRequest($urlSuffix = null, $method = 'GET',
645
                                   $format = null)
646
    {
647
        $this->rowCount = null;
648
649
        if (preg_match('/^http/', $urlSuffix)) {
650
            $url = $urlSuffix;
651
        } else {
652
            $url = $this->getEvidenceURL($urlSuffix);
653
        }
654
655
        $responseCode = $this->doCurlRequest($url, $method, $format);
656
657
        return strlen($this->lastCurlResponse) ? $this->parseResponse($this->rawResponseToArray($this->lastCurlResponse,
658
                    $this->responseFormat), $responseCode) : null;
659
    }
660
661
    /**
662
     * Parse Raw FlexiBee response in several formats
663
     *
664
     * @param string $responseRaw raw response body
665
     * @param string $format      Raw Response format json|xml|etc
666
     *
667
     * @return array
668
     */
669
    public function rawResponseToArray($responseRaw, $format)
670
    {
671
        switch ($format) {
672
            case 'json':
673
                $responseDecoded = json_decode($responseRaw, true, 10);
674
                $decodeError     = json_last_error_msg();
675
                if ($decodeError == 'No error') {
676
                    if (array_key_exists($this->nameSpace, $responseDecoded)) {
677
                        $responseDecoded = $responseDecoded[$this->nameSpace];
678
                    }
679
                } else {
680
                    $this->addStatusMessage('JSON Decoder: '.$decodeError,
681
                        'error');
682
                    $this->addStatusMessage($responseRaw, 'debug');
683
                }
684
                break;
685
            case 'xml':
686
                $responseDecoded = self::xml2array($this->lastCurlResponse);
687
                break;
688
            case 'txt':
689
            default:
690
                $responseDecoded = $this->lastCurlResponse;
691
                break;
692
        }
693
        return $responseDecoded;
694
    }
695
696
    /**
697
     * Parse Response array
698
     *
699
     * @param array $responseDecoded
700
     * @param int $responseCode Request Response Code
701
     *
702
     * @return array main data part of response
703
     */
704
    public function parseResponse($responseDecoded, $responseCode)
705
    {
706
        $response = null;
707
        switch ($responseCode) {
708
            case 201:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
709
                if (isset($responseDecoded[$this->resultField][0]['id'])) {
710
                    $this->lastInsertedID = $responseDecoded[$this->resultField][0]['id'];
711
                    $this->setMyKey($this->lastInsertedID);
712
                    $this->apiURL         = $this->getEvidenceURL().'/'.$this->lastInsertedID;
713
                } else {
714
                    $this->lastInsertedID = null;
715
                    if (isset($responseDecoded['@rowCount'])) {
716
                        $this->rowCount = (int) $responseDecoded['@rowCount'];
717
                    }
718
                }
719
            case 200:
720
                $response         = $this->lastResult = $this->unifyResponseFormat($responseDecoded);
721
                break;
722
723
            case 500:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
724
                if ($this->debug === true) {
725
                    $this->error500Reporter($responseDecoded);
726
                }
727
            case 404:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
728
                if ($this->ignoreNotFound === true) {
729
                    break;
730
                }
731
            case 400:
732
            default: //Something goes wrong
733
                $this->addStatusMessage($this->curlInfo['url'], 'warning');
734
                if (is_array($responseDecoded)) {
735
                    $this->parseError($responseDecoded);
736
                }
737
                $this->logResult($responseDecoded, $this->curlInfo['url']);
738
                break;
739
        }
740
        return $response;
741
    }
742
743
    /**
744
     * Parse error message response
745
     *
746
     * @param array $responseDecoded
747
     * @return int number of errors processed
748
     */
749
    public function parseError(array $responseDecoded)
750
    {
751
        if (array_key_exists('results', $responseDecoded)) {
752
            $this->errors = $responseDecoded['results'][0]['errors'];
753
        } else {
754
            $this->errors = [['message' => $responseDecoded['message']]];
755
        }
756
        return count($this->errors);
757
    }
758
759
    /**
760
     * Vykonej HTTP požadavek
761
     *
762
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Sestavování URL
763
     * @param string $url    URL požadavku
764
     * @param string $method HTTP Method GET|POST|PUT|OPTIONS|DELETE
765
     * @param string $format požadovaný formát komunikace
766
     * @return int HTTP Response CODE
767
     */
768
    public function doCurlRequest($url, $method, $format = null)
769
    {
770
        if (is_null($format)) {
771
            $format = $this->format;
772
        }
773
        curl_setopt($this->curl, CURLOPT_URL, $url);
774
// Nastavení samotné operace
775
        curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, strtoupper($method));
776
//Vždy nastavíme byť i prázná postdata jako ochranu před chybou 411
777
        curl_setopt($this->curl, CURLOPT_POSTFIELDS, $this->postFields);
778
779
        $httpHeaders = $this->defaultHttpHeaders;
780
781
        $formats = Formats::bySuffix();
782
783
        if (!isset($httpHeaders['Accept'])) {
784
            $httpHeaders['Accept'] = $formats[$format]['content-type'];
785
        }
786
        if (!isset($httpHeaders['Content-Type'])) {
787
            $httpHeaders['Content-Type'] = $formats[$format]['content-type'];
788
        }
789
        $httpHeadersFinal = [];
790
        foreach ($httpHeaders as $key => $value) {
791
            if (($key == 'User-Agent') && ($value == 'FlexiPeeHP')) {
792
                $value .= ' v'.self::$libVersion;
793
            }
794
            $httpHeadersFinal[] = $key.': '.$value;
795
        }
796
797
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, $httpHeadersFinal);
798
799
// Proveď samotnou operaci
800
        $this->lastCurlResponse            = curl_exec($this->curl);
801
        $this->curlInfo                    = curl_getinfo($this->curl);
802
        $this->curlInfo['when']            = microtime();
803
        $this->curlInfo['request_headers'] = $httpHeadersFinal;
804
        $this->responseFormat              = Formats::contentTypeToSuffix($this->curlInfo['content_type']);
805
        $this->lastResponseCode            = $this->curlInfo['http_code'];
806
        $this->lastCurlError               = curl_error($this->curl);
807
        if (strlen($this->lastCurlError)) {
808
            $this->addStatusMessage(sprintf('Curl Error (HTTP %d): %s',
809
                    $this->lastResponseCode, $this->lastCurlError), 'error');
810
        }
811
812
        if ($this->debug === true) {
813
            $this->saveDebugFiles();
814
        }
815
816
        return $this->lastResponseCode;
817
    }
818
819
    /**
820
     * Nastaví druh prováděné akce.
821
     *
822
     * @link https://demo.flexibee.eu/devdoc/actions Provádění akcí
823
     * @param string $action
824
     * @return boolean
825
     */
826
    public function setAction($action)
827
    {
828
        $result           = false;
829
        $actionsAvailable = $this->getActionsInfo();
830
        if (array_key_exists($action, $actionsAvailable)) {
831
            $this->action = $action;
832
            $result       = true;
833
        }
834
        return $result;
835
    }
836
837
    /**
838
     * Convert XML to array.
839
     *
840
     * @param string $xml
841
     *
842
     * @return array
843
     */
844
    public static function xml2array($xml)
845
    {
846
        $arr = [];
847
848
        if (is_string($xml)) {
849
            $xml = simplexml_load_string($xml);
850
        }
851
852
        foreach ($xml->children() as $r) {
853
            if (count($r->children()) == 0) {
854
                $arr[$r->getName()] = strval($r);
855
            } else {
856
                $arr[$r->getName()][] = self::xml2array($r);
857
            }
858
        }
859
860
        return $arr;
861
    }
862
863
    /**
864
     * Odpojení od FlexiBee.
865
     */
866
    public function disconnect()
867
    {
868
        if (is_resource($this->curl)) {
869
            curl_close($this->curl);
870
        }
871
        $this->curl = null;
872
    }
873
874
    /**
875
     * Disconnect CURL befere pass away
876
     */
877
    public function __destruct()
878
    {
879
        $this->disconnect();
880
    }
881
882
    /**
883
     * Načte řádek dat z FlexiBee.
884
     *
885
     * @param int $recordID id požadovaného záznamu
886
     *
887
     * @return array
888
     */
889
    public function getFlexiRow($recordID)
890
    {
891
        $record   = null;
892
        $response = $this->performRequest($this->evidence.'/'.$recordID.'.json');
893
        if (isset($response[$this->evidence])) {
894
            $record = $response[$this->evidence][0];
895
        }
896
897
        return $record;
898
    }
899
900
    /**
901
     * Oddělí z pole podmínek ty jenž patří za ? v URL požadavku
902
     *
903
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Sestavování URL
904
     * @param array $conditions pole podmínek   - rendrují se do ()
905
     * @param array $urlParams  pole parametrů  - rendrují za ?
906
     */
907
    public function extractUrlParams(&$conditions, &$urlParams)
908
    {
909
        foreach ($this->urlParams as $urlParam) {
910
            if (isset($conditions[$urlParam])) {
911
                \Ease\Sand::divDataArray($conditions, $urlParams, $urlParam);
912
            }
913
        }
914
    }
915
916
    /**
917
     * Načte data z FlexiBee.
918
     *
919
     * @param string $suffix     dotaz
920
     * @param string|array $conditions Volitelný filtrovací výraz
921
     */
922
    public function getFlexiData($suffix = null, $conditions = null)
923
    {
924
        $urlParams = $this->defaultUrlParams;
925
        if (!is_null($conditions)) {
926
            if (is_array($conditions)) {
927
                $this->extractUrlParams($conditions, $urlParams);
928
                $conditions = $this->flexiUrl($conditions);
929
            }
930
931
            if (strlen($conditions) && ($conditions[0] != '/')) {
932
                $conditions = '/'.rawurlencode('('.($conditions).')');
933
            }
934
        } else {
935
            $conditions = '';
936
        }
937
938
        if (preg_match('/^http/', $suffix)) {
939
            $transactions = $this->performRequest($suffix, 'GET');
940
        } else {
941
            if (strlen($suffix)) {
942
                $transactions = $this->performRequest($this->evidence.$conditions.'.'.$this->format.'?'.$suffix.'&'.http_build_query($urlParams),
943
                    'GET');
944
            } else {
945
                $transactions = $this->performRequest($this->evidence.$conditions.'.'.$this->format.'?'.http_build_query($urlParams),
946
                    'GET');
947
            }
948
        }
949
        $responseEvidence = $this->getResponseEvidence();
950
        if (is_array($transactions) && array_key_exists($responseEvidence,
951
                $transactions)) {
952
            $result = $transactions[$responseEvidence];
953
            if ((count($result) == 1) && (count(current($result)) == 0 )) {
954
                $result = null; // Response is empty Array
955
            }
956
        } else {
957
            $result = $transactions;
958
        }
959
960
        return $result;
961
    }
962
963
    /**
964
     * Načte záznam z FlexiBee a uloží v sobě jeho data
965
     * Read FlexiBee record and store it inside od object
966
     *
967
     * @param int|array $id ID or conditions
968
     *
969
     * @return int počet načtených položek
970
     */
971
    public function loadFromFlexiBee($id = null)
972
    {
973
        $data = [];
974
        if (is_null($id)) {
975
            $id = $this->getMyKey();
976
        }
977
978
        $flexidata = $this->getFlexiData(null, is_array($id) ? $id : '/'.$id);
979
980
        $this->apiURL = $this->curlInfo['url'];
981
        if (is_array($flexidata) && (count($flexidata) == 1)) {
982
            $data = current($flexidata);
983
        }
984
        return $this->takeData($data);
985
    }
986
987
    /**
988
     * Převede data do Json formátu pro FlexiBee.
989
     * Convert data to FlexiBee like Json format
990
     *
991
     * @param array $data
992
     *
993
     * @return string
994
     */
995
    public function jsonizeData($data)
996
    {
997
        $jsonize = [
998
            $this->nameSpace => [
999
                '@version' => $this->protoVersion,
1000
                $this->evidence => $this->objectToID($data),
1001
            ],
1002
        ];
1003
1004 View Code Duplication
        if (!is_null($this->action)) {
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...
1005
            $jsonize[$this->nameSpace][$this->evidence.'@action'] = $this->action;
1006
            $this->action                                         = null;
1007
        }
1008
1009 View Code Duplication
        if (!is_null($this->filter)) {
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...
1010
            $jsonize[$this->nameSpace][$this->evidence.'@filter'] = $this->filter;
1011
        }
1012
1013
        return json_encode($jsonize);
1014
    }
1015
1016
    /**
1017
     * Test if given record ID exists in FlexiBee.
1018
     *
1019
     * @param string|int $identifer
1020
     */
1021
    public function idExists($identifer = null)
1022
    {
1023
        if (is_null($identifer)) {
1024
            $identifer = $this->getMyKey();
1025
        }
1026
        $flexiData = $this->getFlexiData(
1027
            'detail=custom:'.$this->getmyKeyColumn(), $identifer);
1028
1029
        return $flexiData;
1030
    }
1031
1032
    /**
1033
     * Test if given record exists in FlexiBee.
1034
     *
1035
     * @param array $data
1036
     * @return boolean Record presence status
1037
     */
1038
    public function recordExists($data = null)
1039
    {
1040
1041
        if (is_null($data)) {
1042
            $data = $this->getData();
1043
        }
1044
1045
        $res = $this->getColumnsFromFlexibee([$this->myKeyColumn],
1046
            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...
1047
1048
        if (!count($res) || (isset($res['success']) && ($res['success'] == 'false'))
1049
            || !count($res[0])) {
1050
            $found = false;
1051
        } else {
1052
            $found = true;
1053
        }
1054
        return $found;
1055
    }
1056
1057
    /**
1058
     * Vrací z FlexiBee sloupečky podle podmínek.
1059
     *
1060
     * @param array|int|string $conditions pole podmínek nebo ID záznamu
1061
     * @param string           $indexBy    klice vysledku naplnit hodnotou ze
1062
     *                                     sloupečku
1063
     * @return array
1064
     */
1065
    public function getAllFromFlexibee($conditions = null, $indexBy = null)
1066
    {
1067
        if (is_int($conditions)) {
1068
            $conditions = [$this->getmyKeyColumn() => $conditions];
1069
        }
1070
1071
        $flexiData = $this->getFlexiData('', $conditions);
1072
1073
        if (!is_null($indexBy)) {
1074
            $flexiData = $this->reindexArrayBy($flexiData);
1075
        }
1076
1077
        return $flexiData;
1078
    }
1079
1080
    /**
1081
     * Vrací z FlexiBee sloupečky podle podmínek.
1082
     *
1083
     * @param string[] $columnsList seznam položek
1084
     * @param array    $conditions  pole podmínek nebo ID záznamu
1085
     * @param string   $indexBy     Sloupeček podle kterého indexovat záznamy
1086
     *
1087
     * @return array
1088
     */
1089
    public function getColumnsFromFlexibee($columnsList, $conditions = null,
1090
                                           $indexBy = null)
1091
    {
1092
        $detail = 'full';
1093
        switch (gettype($columnsList)) {
1094
            case 'integer':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1095
                $conditions = [$this->getmyKeyColumn() => $conditions];
1096
            case 'array':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1097
                if (!is_null($indexBy) && !array_key_exists($indexBy,
1098
                        $columnsList)) {
1099
                    $columnsList[] = $indexBy;
1100
                }
1101
                $columns = implode(',', array_unique($columnsList));
1102
                $detail  = 'custom:'.$columns;
1103
            default:
1104
                switch ($columnsList) {
1105
                    case 'id':
1106
                        $detail = 'id';
1107
                        break;
1108
                    case 'summary':
1109
                        $detail = 'summary';
1110
                        break;
1111
                    default:
1112
                        break;
1113
                }
1114
                break;
1115
        }
1116
1117
        $flexiData = $this->getFlexiData('detail='.$detail, $conditions);
1118
1119
        if (!is_null($indexBy) && count($flexiData) && count(current($flexiData))) {
1120
            $flexiData = $this->reindexArrayBy($flexiData, $indexBy);
1121
        }
1122
1123
        return $flexiData;
1124
    }
1125
1126
    /**
1127
     * Vrací kód záznamu.
1128
     *
1129
     * @param mixed $data
1130
     *
1131
     * @return string
1132
     */
1133
    public function getKod($data = null, $unique = true)
1134
    {
1135
        $kod = null;
1136
1137
        if (is_null($data)) {
1138
            $data = $this->getData();
1139
        }
1140
1141
        if (is_string($data)) {
1142
            $data = [$this->nameColumn => $data];
1143
        }
1144
1145
        if (isset($data['kod'])) {
1146
            $kod = $data['kod'];
1147
        } else {
1148
            if (isset($data[$this->nameColumn])) {
1149
                $kod = preg_replace('/[^a-zA-Z0-9]/', '',
1150
                    \Ease\Sand::rip($data[$this->nameColumn]));
1151
            } else {
1152
                if (isset($data[$this->myKeyColumn])) {
1153
                    $kod = \Ease\Sand::rip($data[$this->myKeyColumn]);
1154
                }
1155
            }
1156
        }
1157
1158
        if (!strlen($kod)) {
1159
            $kod = 'NOTSET';
1160
        }
1161
1162
        if (strlen($kod) > 18) {
1163
            $kodfinal = strtoupper(substr($kod, 0, 18));
1164
        } else {
1165
            $kodfinal = strtoupper($kod);
1166
        }
1167
1168
        if ($unique) {
1169
            $counter = 0;
1170
            if (count($this->codes)) {
1171
                foreach ($this->codes as $codesearch => $keystring) {
1172
                    if (strstr($codesearch, $kodfinal)) {
1173
                        ++$counter;
1174
                    }
1175
                }
1176
            }
1177
            if ($counter) {
1178
                $kodfinal = $kodfinal.$counter;
1179
            }
1180
1181
            $this->codes[$kodfinal] = $kod;
1182
        }
1183
1184
        return $kodfinal;
1185
    }
1186
1187
    /**
1188
     * Write Operation Result.
1189
     *
1190
     * @param array  $resultData
1191
     * @param string $url        URL
1192
     * @return boolean Log save success
1193
     */
1194
    public function logResult($resultData = null, $url = null)
1195
    {
1196
        $logResult = false;
1197
        if (isset($resultData['success']) && ($resultData['success'] == 'false')) {
1198
            if (isset($resultData['message'])) {
1199
                $this->addStatusMessage($resultData['message'], 'warning');
1200
            }
1201
            $this->addStatusMessage('Error '.$this->lastResponseCode.': '.urldecode($url),
1202
                'warning');
1203
            unset($url);
1204
        }
1205
        if (is_null($resultData)) {
1206
            $resultData = $this->lastResult;
1207
        }
1208
        if (isset($url)) {
1209
            $this->logger->addStatusMessage(urldecode($url));
1210
        }
1211
1212
        if (isset($resultData['results'])) {
1213
            if ($resultData['success'] == 'false') {
1214
                $status = 'error';
1215
            } else {
1216
                $status = 'success';
1217
            }
1218
            foreach ($resultData['results'] as $result) {
1219
                if (isset($result['request-id'])) {
1220
                    $rid = $result['request-id'];
1221
                } else {
1222
                    $rid = '';
1223
                }
1224
                if (isset($result['errors'])) {
1225
                    foreach ($result['errors'] as $error) {
1226
                        $message = $error['message'];
1227
                        if (isset($error['for'])) {
1228
                            $message .= ' for: '.$error['for'];
1229
                        }
1230
                        if (isset($error['value'])) {
1231
                            $message .= ' value:'.$error['value'];
1232
                        }
1233
                        if (isset($error['code'])) {
1234
                            $message .= ' code:'.$error['code'];
1235
                        }
1236
                        $this->addStatusMessage($rid.': '.$message, $status);
1237
                    }
1238
                }
1239
            }
1240
        }
1241
        return $logResult;
1242
    }
1243
1244
    /**
1245
     * Save RAW Curl Request & Response to files in Temp directory
1246
     */
1247
    public function saveDebugFiles()
1248
    {
1249
        $tmpdir   = sys_get_temp_dir();
1250
        $fname    = $this->evidence.'-'.$this->curlInfo['when'].'.'.$this->format;
1251
        $reqname  = $tmpdir.'/request-'.$fname;
1252
        $respname = $tmpdir.'/response-'.$fname;
1253
        file_put_contents($reqname, $this->postFields);
1254
        file_put_contents($respname, $this->lastCurlResponse);
1255
    }
1256
1257
    /**
1258
     * Připraví data pro odeslání do FlexiBee
1259
     *
1260
     * @param string $data
1261
     */
1262
    public function setPostFields($data)
1263
    {
1264
        $this->postFields = $data;
1265
    }
1266
1267
    /**
1268
     * Generuje fragment url pro filtrování.
1269
     *
1270
     * @see https://www.flexibee.eu/api/dokumentace/ref/filters
1271
     *
1272
     * @param array  $data
1273
     * @param string $joiner default and/or
1274
     * @param string $defop  default operator
1275
     *
1276
     * @return string
1277
     */
1278
    public static function flexiUrl(array $data, $joiner = 'and', $defop = 'eq')
1279
    {
1280
        $parts = [];
1281
1282
        foreach ($data as $column => $value) {
1283
            if (is_integer($data[$column]) || is_float($data[$column])) {
1284
                $parts[$column] = $column.' eq \''.$data[$column].'\'';
1285
            } elseif (is_bool($data[$column])) {
1286
                $parts[$column] = $data[$column] ? $column.' eq true' : $column.' eq false';
1287
            } elseif (is_null($data[$column])) {
1288
                $parts[$column] = $column." is null";
1289
            } else {
1290
                switch ($value) {
1291
                    case '!null':
1292
                        $parts[$column] = $column." is not null";
1293
                        break;
1294
                    case 'is empty':
1295
                    case 'is not empty':
1296
                        $parts[$column] = $column.' '.$value;
1297
                        break;
1298
                    default:
1299
                        if ($column == 'stitky') {
1300
                            $parts[$column] = $column."='code:".$data[$column]."'";
1301
                        } else {
1302
                            $parts[$column] = $column." $defop '".$data[$column]."'";
1303
                        }
1304
                        break;
1305
                }
1306
            }
1307
        }
1308
        return implode(' '.$joiner.' ', $parts);
1309
    }
1310
1311
    /**
1312
     * Obtain record/object identificator code: or id:
1313
     * Vrací identifikátor objektu code: nebo id:
1314
     *
1315
     * @link https://demo.flexibee.eu/devdoc/identifiers Identifikátory záznamů
1316
     * @return string|int indentifikátor záznamu reprezentovaného objektem
1317
     */
1318
    public function getRecordID()
1319
    {
1320
        $myCode = $this->getDataValue('kod');
1321
        if ($myCode) {
1322
            $id = 'code:'.$myCode;
1323
        } else {
1324
            $id = $this->getDataValue('id');
1325
            if (($this->debug === true) && is_null($id)) {
1326
                $this->addToLog('Object Data does not contain code: or id: cannot match with statement!',
1327
                    'warning');
1328
            }
1329
        }
1330
        return is_numeric($id) ? intval($id) : strval($id);
1331
    }
1332
1333
    /**
1334
     * Obtain record/object identificator code: or id:
1335
     * Vrací identifikátor objektu code: nebo id:
1336
     *
1337
     * @link https://demo.flexibee.eu/devdoc/identifiers Identifikátory záznamů
1338
     * @return string indentifikátor záznamu reprezentovaného objektem
1339
     */
1340
    public function __toString()
1341
    {
1342
        return strval($this->getRecordID());
1343
    }
1344
1345
    /**
1346
     * Gives you FlexiPeeHP class name for Given Evidence
1347
     *
1348
     * @param string $evidence
1349
     * @return string Class name
1350
     */
1351
    public static function evidenceToClassName($evidence)
1352
    {
1353
        return str_replace(' ', '', ucwords(str_replace('-', ' ', $evidence)));
1354
    }
1355
1356
    /**
1357
     * Vrací hodnotu daného externího ID
1358
     *
1359
     * @param string $want Which ? If empty,you obtain the first one.
1360
     * @return string
1361
     */
1362
    public function getExternalID($want = null)
1363
    {
1364
        $extid = null;
1365
        $ids   = $this->getDataValue('external-ids');
1366
        if (is_null($want)) {
1367
            if (count($ids)) {
1368
                $extid = current($ids);
1369
            }
1370
        } else {
1371
            if (!is_null($ids) && is_array($ids)) {
1372
                foreach ($ids as $id) {
1373
                    if (strstr($id, 'ext:'.$want)) {
1374
                        $extid = str_replace('ext:'.$want.':', '', $id);
1375
                    }
1376
                }
1377
            }
1378
        }
1379
        return $extid;
1380
    }
1381
1382
    /**
1383
     * Obtain actual GlobalVersion
1384
     * Vrací aktuální globální verzi změn
1385
     *
1386
     * @link https://www.flexibee.eu/api/dokumentace/ref/changes-api#globalVersion Globální Verze
1387
     * @return type
1388
     */
1389
    public function getGlobalVersion()
1390
    {
1391
        $globalVersion = null;
1392
        if (!count($this->lastResult) || !isset($this->lastResult['@globalVersion'])) {
1393
            $this->getFlexiData(null,
1394
                ['add-global-version' => 'true', 'limit' => 1]);
1395
        }
1396
1397
        if (isset($this->lastResult['@globalVersion'])) {
1398
            $globalVersion = intval($this->lastResult['@globalVersion']);
1399
        }
1400
1401
        return $globalVersion;
1402
    }
1403
1404
    /**
1405
     * Obtain content type of last response
1406
     *
1407
     * @return string
1408
     */
1409
    public function getResponseFormat()
1410
    {
1411
        if (isset($this->curlInfo['content_type'])) {
1412
            $responseFormat = $this->curlInfo['content_type'];
1413
        } else {
1414
            $responseFormat = null;
1415
        }
1416
        return $responseFormat;
1417
    }
1418
1419
    /**
1420
     * Return the same response format for one and multiplete results
1421
     *
1422
     * @param array $responseBody
1423
     * @return array
1424
     */
1425
    public function unifyResponseFormat($responseBody)
1426
    {
1427
        if (!is_array($responseBody) || array_key_exists('message',
1428
                $responseBody)) { //Unifi response format
1429
            $response = $responseBody;
1430
        } else {
1431
            $evidence = $this->getResponseEvidence();
1432
            if (array_key_exists($evidence, $responseBody)) {
1433
                $response        = [];
1434
                $evidenceContent = $responseBody[$evidence];
1435
                if (array_key_exists(0, $evidenceContent)) {
1436
                    $response[$evidence] = $evidenceContent; //Multiplete Results
1437
                } else {
1438
                    $response[$evidence][0] = $evidenceContent; //One result
1439
                }
1440
            } else {
1441
                if (isset($responseBody['priloha'])) {
1442
                    $response = $responseBody['priloha'];
1443
                } else {
1444
                    $response = $responseBody;
1445
                }
1446
            }
1447
        }
1448
        return $response;
1449
    }
1450
1451
    /**
1452
     * Obtain structure for current (or given) evidence
1453
     *
1454
     * @param string $evidence
1455
     * @return array Evidence structure
1456
     */
1457 View Code Duplication
    public function getColumnsInfo($evidence = 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...
1458
    {
1459
        $columnsInfo = null;
1460
        if (is_null($evidence)) {
1461
            $evidence = $this->getEvidence();
1462
        }
1463
        $propsName = lcfirst(FlexiBeeRO::evidenceToClassName($evidence));
1464
        if (isset(\FlexiPeeHP\Properties::$$propsName)) {
1465
            $columnsInfo = Properties::$$propsName;
1466
        }
1467
        return $columnsInfo;
1468
    }
1469
1470
    /**
1471
     * Obtain actions for current (or given) evidence
1472
     *
1473
     * @param string $evidence
1474
     * @return array Evidence structure
1475
     */
1476 View Code Duplication
    public function getActionsInfo($evidence = 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...
1477
    {
1478
        $actionsInfo = null;
1479
        if (is_null($evidence)) {
1480
            $evidence = $this->getEvidence();
1481
        }
1482
        $propsName = lcfirst(FlexiBeeRO::evidenceToClassName($evidence));
1483
        if (isset(\FlexiPeeHP\Actions::$$propsName)) {
1484
            $actionsInfo = Actions::$$propsName;
1485
        }
1486
        return $actionsInfo;
1487
    }
1488
1489
    /**
1490
     * Obtain relations for current (or given) evidence
1491
     *
1492
     * @param string $evidence
1493
     * @return array Evidence structure
1494
     */
1495
    public function getRelationsInfo($evidence = null)
1496
    {
1497
        $relationsInfo = null;
1498
        if (is_null($evidence)) {
1499
            $evidence = $this->getEvidence();
1500
        }
1501
        $propsName = lcfirst(FlexiBeeRO::evidenceToClassName($evidence));
1502
        if (isset(\FlexiPeeHP\Relations::$$propsName)) {
1503
            $relationsInfo = Relations::$$propsName;
1504
        }
1505
        return $relationsInfo;
1506
    }
1507
1508
    /**
1509
     * Obtain info for current (or given) evidence
1510
     *
1511
     * @param string $evidence
1512
     * @return array Evidence info
1513
     */
1514 View Code Duplication
    public function getEvidenceInfo($evidence = 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...
1515
    {
1516
        $evidencesInfo = null;
1517
        if (is_null($evidence)) {
1518
            $evidence = $this->getEvidence();
1519
        }
1520
        if (isset(EvidenceList::$evidences[$evidence])) {
1521
            $evidencesInfo = EvidenceList::$evidences[$evidence];
1522
        }
1523
        return $evidencesInfo;
1524
    }
1525
1526
    /**
1527
     * Obtain name for current (or given) evidence path
1528
     *
1529
     * @param string $evidence Evidence Path
1530
     * @return array Evidence info
1531
     */
1532 View Code Duplication
    public function getEvidenceName($evidence = 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...
1533
    {
1534
        $evidenceName = null;
1535
        if (is_null($evidence)) {
1536
            $evidence = $this->getEvidence();
1537
        }
1538
        if (isset(EvidenceList::$name[$evidence])) {
1539
            $evidenceName = EvidenceList::$name[$evidence];
1540
        }
1541
        return $evidenceName;
1542
    }
1543
1544
    /**
1545
     * Perform given action (if availble) on current evidence/record
1546
     * @url https://demo.flexibee.eu/devdoc/actions
1547
     *
1548
     * @param string $action one of evidence actions
1549
     * @param string $method ext|int External method call operation in URL.
1550
     *                               Internal add the @action element to request body
1551
     */
1552
    public function performAction($action, $method = 'ext')
1553
    {
1554
        $actionsAvailble = $this->getActionsInfo();
1555
1556
        if (is_array($actionsAvailble) && array_key_exists($action,
1557
                $actionsAvailble)) {
1558
            switch ($actionsAvailble[$action]['actionMakesSense']) {
1559
                case 'ONLY_WITH_INSTANCE_AND_NOT_IN_EDIT':
1560
                case 'ONLY_WITH_INSTANCE': //Add instance
1561
                    $urlSuffix = '/'.$this->__toString().'/'.$action.'.'.$this->format;
1562
                    break;
1563
1564
                default:
1565
                    $urlSuffix = '/'.$action;
1566
                    break;
1567
            }
1568
1569
            switch ($method) {
1570
                case 'int':
1571
                    $this->setAction($action);
1572
                    $this->setPostFields($this->jsonizeData($this->getData()));
1573
                    $result = $this->performRequest(null, 'POST');
1574
                    break;
1575
1576
                default:
1577
                    $result = $this->performRequest($urlSuffix, 'GET');
1578
                    break;
1579
            }
1580
        } else {
1581
            throw new \Exception(sprintf(_('Unsupported action %s for evidence %s'),
1582
                $action, $this->getEvidence()));
1583
        }
1584
1585
        return $result;
1586
    }
1587
1588
    /**
1589
     * Save current object to file
1590
     *
1591
     * @param string $destfile path to file
1592
     */
1593
    public function saveResponseToFile($destfile)
1594
    {
1595
        if (strlen($this->lastCurlResponse)) {
1596
            $this->doCurlRequest($this->apiURL, 'GET', $this->format);
1597
        }
1598
        file_put_contents($destfile, $this->lastCurlResponse);
1599
    }
1600
1601
    /**
1602
     * Obtain established relations listing
1603
     *
1604
     * @return array Null or Relations
1605
     */
1606
    public function getVazby()
1607
    {
1608
        $vazby = $this->getDataValue('vazby');
1609
        if (is_null($vazby)) {
1610
            $vazby = $this->getColumnsFromFlexibee('*',
0 ignored issues
show
Documentation introduced by
'*' is of type string, but the function expects a array<integer,string>.

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...
1611
                ['relations' => 'vazby', 'id' => $this->getRecordID()]);
1612
            $vazby = $vazby[0]['vazby'];
1613
        }
1614
        return $vazby;
1615
    }
1616
1617
    /**
1618
     * Gives You URL for Current Record in FlexiBee web interface
1619
     *
1620
     * @return string url
1621
     */
1622
    public function getFlexiBeeURL()
1623
    {
1624
        $parsed_url = parse_url(str_replace('.'.$this->format, '', $this->apiURL));
1625
        $scheme     = isset($parsed_url['scheme']) ? $parsed_url['scheme'].'://'
1626
                : '';
1627
        $host       = isset($parsed_url['host']) ? $parsed_url['host'] : '';
1628
        $port       = isset($parsed_url['port']) ? ':'.$parsed_url['port'] : '';
1629
        $user       = isset($parsed_url['user']) ? $parsed_url['user'] : '';
1630
        $pass       = isset($parsed_url['pass']) ? ':'.$parsed_url['pass'] : '';
1631
        $pass       = ($user || $pass) ? "$pass@" : '';
1632
        $path       = isset($parsed_url['path']) ? $parsed_url['path'] : '';
1633
        return $scheme.$user.$pass.$host.$port.$path;
1634
    }
1635
1636
    /**
1637
     * Set Record Key
1638
     *
1639
     * @param int|string $myKeyValue
1640
     * @return boolean
1641
     */
1642
    public function setMyKey($myKeyValue)
1643
    {
1644
        $res = parent::setMyKey($myKeyValue);
1645
        $this->updateApiURL();
1646
        return $res;
1647
    }
1648
1649
    /**
1650
     * Set or get ignore not found pages flag
1651
     *
1652
     * @param boolean $ignore set flag to
1653
     *
1654
     * @return boolean get flag state
1655
     */
1656
    public function ignore404($ignore = null)
1657
    {
1658
        if (!is_null($ignore)) {
1659
            $this->ignoreNotFound = $ignore;
1660
        }
1661
        return $this->ignoreNotFound;
1662
    }
1663
1664
    /**
1665
     * Send Document by mail
1666
     *
1667
     * @url https://www.flexibee.eu/api/dokumentace/ref/odesilani-mailem/
1668
     *
1669
     * @param string $to
1670
     * @param string $subject
1671
     * @param string $body Email Text
1672
     *
1673
     * @return int http response code
1674
     */
1675
    public function sendByMail($to, $subject, $body, $cc = null)
1676
    {
1677
        $this->setPostFields($body);
1678
        $result = $this->doCurlRequest($this->getEvidenceURL().'/'.
1679
            urlencode($this->getRecordID()).'/odeslani-dokladu?to='.$to.'&subject='.urlencode($subject).'&cc='.$cc
1680
            , 'PUT', 'xml');
1681
        return $result == 200;
1682
    }
1683
1684
    /**
1685
     * Send all unsent Invoices by mail
1686
     *
1687
     * @url https://www.flexibee.eu/api/dokumentace/ref/odesilani-mailem/
1688
     * @return int http response code
1689
     */
1690
    public function sendUnsent()
1691
    {
1692
        return $this->doCurlRequest($this->getEvidenceURL().'/automaticky-odeslat-neodeslane',
1693
                'PUT', 'xml');
1694
    }
1695
1696
    /**
1697
     * FlexiBee date to PHP DateTime
1698
     *
1699
     * @param string $flexidate
1700
     * @return \DateTime
1701
     */
1702
    public static function flexiDateToDateTime($flexidate)
1703
    {
1704
        return \DateTime::createFromFormat('Y-m-jO', $flexidate);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression \DateTime::createFromFor...('Y-m-jO', $flexidate); of type DateTime|false adds false to the return on line 1704 which is incompatible with the return type documented by FlexiPeeHP\FlexiBeeRO::flexiDateToDateTime of type DateTime. It seems like you forgot to handle an error condition.
Loading history...
1705
    }
1706
1707
    /**
1708
     * Získá dokument v daném formátu
1709
     * Obtain document in given format
1710
     *
1711
     * @param string $format  pdf/csv/xml/json/ ...
1712
     *
1713
     * @return string|null filename downloaded or none
1714
     */
1715
    public function getInFormat($format)
1716
    {
1717
        $response = null;
1718
        if ($this->setFormat($format)) {
1719
            if (($this->doCurlRequest(($format == 'html') ? $this->apiURL.'?inDesktopApp=true'
1720
                            : $this->apiURL, 'GET') == 200)) {
1721
                $response = $this->lastCurlResponse;
1722
            }
1723
        }
1724
        return $response;
1725
    }
1726
1727
    /**
1728
     * Uloží dokument v daném formátu do složky v systému souborů
1729
     * Save document in given format to directory in filesystem
1730
     *
1731
     * @param string $format  pdf/csv/xml/json/ ...
1732
     * @param string $destDir where to put file (prefix)
1733
     *
1734
     * @return string|null filename downloaded or none
1735
     */
1736
    public function downloadInFormat($format, $destDir = './')
1737
    {
1738
        $fileOnDisk = null;
1739
        if ($this->setFormat($format)) {
1740
            $downloadTo = $destDir.$this->getEvidence().'_'.$this->getMyKey().'.'.$format;
1741
            if (($this->doCurlRequest($this->apiURL, 'GET') == 200) && (file_put_contents($downloadTo,
1742
                    $this->lastCurlResponse) !== false)) {
1743
                $fileOnDisk = $downloadTo;
1744
            }
1745
        }
1746
        return $fileOnDisk;
1747
    }
1748
1749
    /**
1750
     * Compile and send Report about Error500 to FlexiBee developers
1751
     * If FlexiBee is running on localost try also include java backtrace
1752
     *
1753
     * @param array $errorResponse result of parseError();
1754
     */
1755
    public function error500Reporter($errorResponse)
1756
    {
1757
        $ur = str_replace('/c/'.$this->company, '',
1758
            str_replace($this->url, '', $this->curlInfo['url']));
1759
        if (!array_key_exists($ur, $this->reports)) {
1760
            $tmpdir   = sys_get_temp_dir();
1761
            $myTime   = $this->curlInfo['when'];
1762
            $curlname = $tmpdir.'/curl-'.$this->evidence.'-'.$myTime.'.json';
1763
            file_put_contents($curlname,
1764
                json_encode($this->curlInfo, JSON_PRETTY_PRINT));
1765
1766
            $report = new \Ease\Mailer($this->reportRecipient,
1767
                'Error report 500 - '.$ur);
1768
1769
            $d     = dir($tmpdir);
1770
            while (false !== ($entry = $d->read())) {
1771
                if (strstr($entry, $myTime)) {
1772
                    $ext  = pathinfo($tmpdir.'/'.$entry, PATHINFO_EXTENSION);
1773
                    $mime = Formats::suffixToContentType($ext);
1774
                    $report->addFile($tmpdir.'/'.$entry,
1775
                        empty($mime) ? 'text/plain' : $mime);
1776
                }
1777
            }
1778
            $d->close();
1779
1780
            if ((strstr($this->url, '://localhost') || strstr($this->url,
1781
                    '://127.')) && file_exists('/var/log/flexibee.log')) {
1782
1783
                $fl = fopen("/var/log/flexibee.log", "r");
1784
                if ($fl) {
1785
                    $tracelog = [];
1786
                    for ($x_pos = 0, $ln = 0, $output = array(); fseek($fl,
1787
                            $x_pos, SEEK_END) !== -1; $x_pos--) {
1788
                        $char = fgetc($fl);
1789
                        if ($char === "\n") {
1790
                            $tracelog[] = $output[$ln];
1791
                            if (strstr($output[$ln], $errorResponse['message'])) {
1792
                                break;
1793
                            }
1794
                            $ln++;
1795
                            continue;
1796
                        }
1797
                        $output[$ln] = $char.((array_key_exists($ln, $output)) ? $output[$ln]
1798
                                : '');
1799
                    }
1800
1801
                    $trace     = implode("\n", array_reverse($tracelog));
1802
                    $tracefile = $tmpdir.'/trace-'.$this->evidence.'-'.$myTime.'.log';
1803
                    file_put_contents($tracefile, $trace);
1804
                    $report->addItem("\n\n".$trace);
1805
                    fclose($fl);
1806
                }
1807
            } else {
1808
                $report->addItem($errorResponse['message']);
1809
            }
1810
1811
            $licenseInfo = $this->performRequest($this->url.'/default-license.json');
1812
1813
            $report->addItem("\n\n".json_encode($licenseInfo['license'],
1814
                    JSON_PRETTY_PRINT));
1815
1816
            if ($report->send()) {
1817
                $this->reports[$ur] = $myTime;
1818
            }
1819
        }
1820
    }
1821
}
1822