Test Failed
Push — master ( 66a8dd...55f2dd )
by Vítězslav
12:54
created

FlexiBeeRO   D

Complexity

Total Complexity 296

Size/Duplication

Total Lines 1964
Duplicated Lines 1.48 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 73.79%

Importance

Changes 0
Metric Value
dl 29
loc 1964
ccs 642
cts 870
cp 0.7379
rs 4.4102
c 0
b 0
f 0
wmc 296
lcom 1
cbo 6

71 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 2
A setUp() 0 16 3
B setupProperty() 0 10 5
A curlInit() 0 12 1
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() 0 20 6
A objectToID() 0 17 4
A getEvidenceURL() 0 9 2
B evidenceUrlWithSuffix() 0 12 5
A updateApiURL() 0 9 2
A performRequest() 0 18 4
A rawResponseToArray() 0 16 4
A rawJsonToArray() 0 14 3
A rawXmlToArray() 0 4 1
C parseResponse() 0 42 12
A parseError() 0 11 3
C doCurlRequest() 0 51 10
A setAction() 0 11 3
B xml2array() 0 18 5
A disconnect() 0 7 2
A __destruct() 0 4 1
A getFlexiRow() 0 10 2
A extractUrlParams() 0 8 3
A urlEncode() 0 4 1
C getFlexiData() 0 53 16
B loadFromFlexiBee() 0 21 6
A jsonizeData() 7 20 3
A idExists() 0 13 2
B recordExists() 0 18 6
A getAllFromFlexibee() 0 14 3
D getColumnsFromFlexibee() 0 38 10
D getKod() 0 53 13
C logResult() 0 49 15
A saveDebugFiles() 0 9 1
A setPostFields() 0 4 1
C flexiUrl() 0 36 12
B getRecordID() 0 14 5
A __toString() 0 4 1
A evidenceToClassName() 0 4 1
A getFirstRecordID() 0 10 2
B getExternalID() 0 19 7
A getGlobalVersion() 0 6 1
A getResponseFormat() 0 9 2
C unifyResponseFormat() 0 29 7
A getColumnsInfo() 0 10 3
A getActionsInfo() 0 12 3
A getRelationsInfo() 0 12 3
A getEvidenceInfo() 11 11 3
A getEvidenceName() 11 11 3
B performAction() 0 36 6
A saveResponseToFile() 0 7 2
A getVazby() 0 15 4
C getFlexiBeeURL() 0 13 9
A setMyKey() 0 6 1
A ignore404() 0 7 2
A sendByMail() 0 7 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
A code() 0 4 1
A uncode() 0 4 1
A __wakeup() 0 5 1

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
     * Where to get JSON files with evidence stricture etc.
20
     * @var string
21
     */
22
    public static $infoDir = __DIR__.'/../../static';
23
24
    /**
25
     * Version of FlexiPeeHP library
26
     *
27
     * @var string
28
     */
29
    public static $libVersion = '1.8.4.3';
30
31
    /**
32
     * Základní namespace pro komunikaci s FlexiBee.
33
     * Basic namespace for communication with FlexiBee
34
     *
35
     * @var string Jmený prostor datového bloku odpovědi
36
     */
37
    public $nameSpace = 'winstrom';
38
39
    /**
40
     * URL of object data in FlexiBee
41
     * @var string url
42
     */
43
    public $apiURL = null;
44
45
    /**
46
     * Datový blok v poli odpovědi.
47
     * Data block in response field.
48
     *
49
     * @var string
50
     */
51
    public $resultField = 'results';
52
53
    /**
54
     * Verze protokolu použitého pro komunikaci.
55
     * Communication protocol version used.
56
     *
57
     * @var string Verze použitého API
58
     */
59
    public $protoVersion = '1.0';
60
61
    /**
62
     * Evidence užitá objektem.
63
     * Evidence used by object
64
     *
65
     * @link https://demo.flexibee.eu/c/demo/evidence-list Přehled evidencí
66
     * @var string
67
     */
68
    public $evidence = null;
69
70
    /**
71
     * Výchozí formát pro komunikaci.
72
     * Default communication format.
73
     *
74
     * @link https://www.flexibee.eu/api/dokumentace/ref/format-types Přehled možných formátů
75
     *
76
     * @var string json|xml|...
77
     */
78
    public $format = 'json';
79
80
    /**
81
     * formát příchozí odpovědi
82
     * response format
83
     *
84
     * @link https://www.flexibee.eu/api/dokumentace/ref/format-types Přehled možných formátů
85
     *
86
     * @var string json|xml|...
87
     */
88
    public $responseFormat = 'json';
89
90
    /**
91
     * Curl Handle.
92
     *
93
     * @var resource
94
     */
95
    public $curl = null;
96
97
    /**
98
     * @link https://demo.flexibee.eu/devdoc/company-identifier Identifikátor firmy
99
     * @var string
100
     */
101
    public $company = null;
102
103
    /**
104
     * Server[:port]
105
     * @var string
106
     */
107
    public $url = null;
108
109
    /**
110
     * REST API Username
111
     * @var string
112
     */
113
    public $user = null;
114
115
    /**
116
     * REST API Password
117
     * @var string
118
     */
119
    public $password = null;
120
121
    /**
122
     * @var array Pole HTTP hlaviček odesílaných s každým požadavkem
123
     */
124
    public $defaultHttpHeaders = ['User-Agent' => 'FlexiPeeHP'];
125
126
    /**
127
     * Default additional request url parameters after question mark
128
     *
129
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls   Common params
130
     * @link https://www.flexibee.eu/api/dokumentace/ref/paging Paging params
131
     * @var array
132
     */
133
    public $defaultUrlParams = ['limit' => 0];
134
135
    /**
136
     * Identifikační řetězec.
137
     *
138
     * @var string
139
     */
140
    public $init = null;
141
142
    /**
143
     * Sloupeček s názvem.
144
     *
145
     * @var string
146
     */
147
    public $nameColumn = 'nazev';
148
149
    /**
150
     * Sloupeček obsahující datum vložení záznamu do shopu.
151
     *
152
     * @var string
153
     */
154
    public $myCreateColumn = 'false';
155
156
    /**
157
     * Slopecek obsahujici datum poslení modifikace záznamu do shopu.
158
     *
159
     * @var string
160
     */
161
    public $myLastModifiedColumn = 'lastUpdate';
162
163
    /**
164
     * Klíčový idendifikátor záznamu.
165
     *
166
     * @var string
167
     */
168
    public $fbKeyColumn = 'id';
169
170
    /**
171
     * Informace o posledním HTTP requestu.
172
     *
173
     * @var *
174
     */
175
    public $curlInfo;
176
177
    /**
178
     * Informace o poslední HTTP chybě.
179
     *
180
     * @var string
181
     */
182
    public $lastCurlError = null;
183
184
    /**
185
     * Used codes storage.
186
     *
187
     * @var array
188
     */
189
    public $codes = null;
190
191
    /**
192
     * Last Inserted ID.
193
     *
194
     * @var int
195
     */
196
    public $lastInsertedID = null;
197
198
    /**
199
     * Default Line Prefix.
200
     *
201
     * @var string
202
     */
203
    public $prefix = '/c/';
204
205
    /**
206
     * Raw Content of last curl response
207
     *
208
     * @var string
209
     */
210
    public $lastCurlResponse;
211
212
    /**
213
     * HTTP Response code of last request
214
     *
215
     * @var int
216
     */
217
    public $lastResponseCode = null;
218
219
    /**
220
     * Body data  for next curl POST operation
221
     *
222
     * @var string
223
     */
224
    protected $postFields = null;
225
226
    /**
227
     * Last operation result data or message(s)
228
     *
229
     * @var array
230
     */
231
    public $lastResult = null;
232
233
    /**
234
     * Number from  @rowCount in response
235
     * @var int
236
     */
237
    public $rowCount = null;
238
239
    /**
240
     * Number from  @globalVersion
241
     * @var int
242
     */
243
    public $globalVersion = null;
244
245
    /**
246
     * @link https://www.flexibee.eu/api/dokumentace/ref/zamykani-odemykani/
247
     * @var string filter query
248
     */
249
    public $filter;
250
251
    /**
252
     * @link https://demo.flexibee.eu/devdoc/actions Provádění akcí
253
     * @var string
254
     */
255
    protected $action;
256
257
    /**
258
     * Pole akcí které podporuje ta která evidence
259
     * @link https://demo.flexibee.eu/c/demo/faktura-vydana/actions.json Např. Akce faktury
260
     * @var array
261
     */
262
    public $actionsAvailable = null;
263
264
    /**
265
     * Parmetry pro URL
266
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Všechny podporované parametry
267
     * @var array
268
     */
269
    public $urlParams = [
270
        'idUcetniObdobi',
271
        'dry-run',
272
        'fail-on-warning',
273
        'report-name',
274
        'report-lang',
275
        'report-sign',
276
        'detail', //See: https://www.flexibee.eu/api/dokumentace/ref/detail-levels
277
        'mode',
278
        'limit',
279
        'start',
280
        'order',
281
        'sort',
282
        'add-row-count',
283
        'relations',
284
        'includes',
285
        'use-ext-id',
286
        'use-internal-id',
287
        'stitky-as-ids',
288
        'only-ext-ids',
289
        'no-ext-ids',
290
        'no-ids',
291
        'code-as-id',
292
        'no-http-errors',
293
        'export-settings',
294
        'as-gui',
295
        'code-in-response',
296
        'add-global-version',
297
        'encoding',
298
        'delimeter',
299
        'format',
300
        'auth',
301
        'skupina-stitku',
302
        'dir',
303
        'relations',
304
        'relations',
305
        'xpath', // See: https://www.flexibee.eu/api/dokumentace/ref/xpath/
306
        'dry-run', // See: https://www.flexibee.eu/api/dokumentace/ref/dry-run/
307
        'inDesktopApp' // Note: Undocumented function (html only)
308
    ];
309
310
    /**
311
     * Save 404 results to log ?
312
     * @var boolean
313
     */
314
    protected $ignoreNotFound = false;
315
316
    /**
317
     * Array of errors caused by last request
318
     * @var array
319
     */
320
    private $errors = [];
321
322
    /**
323
     * List of Error500 reports sent
324
     * @var array
325
     */
326
    private $reports = [];
327
328
    /**
329
     * Send Error500 Report to
330
     * @var string email address
331
     */
332
    public $reportRecipient = '[email protected]';
333
334
    /**
335
     * Class for read only interaction with FlexiBee.
336
     *
337
     * @param mixed $init default record id or initial data
338
     * @param array $options Connection settings override
339
     */
340 24
    public function __construct($init = null, $options = [])
341
    {
342 24
        $this->init = $init;
343
344 24
        parent::__construct();
345 24
        $this->setUp($options);
346 24
        $this->curlInit();
347 24
        if (!empty($init)) {
348 22
            $this->processInit($init);
349 22
        }
350 24
    }
351
352
    /**
353
     * SetUp Object to be ready for connect
354
     *
355
     * @param array $options Object Options (company,url,user,password,evidence,
356
     *                                       prefix,defaultUrlParams,debug)
357
     */
358 47
    public function setUp($options = [])
359
    {
360 47
        $this->setupProperty($options, 'company', 'FLEXIBEE_COMPANY');
361 47
        $this->setupProperty($options, 'url', 'FLEXIBEE_URL');
362 47
        $this->setupProperty($options, 'user', 'FLEXIBEE_LOGIN');
363 47
        $this->setupProperty($options, 'password', 'FLEXIBEE_PASSWORD');
364 47
        if (isset($options['evidence'])) {
365 45
            $this->setEvidence($options['evidence']);
366 45
        }
367 47
        $this->setupProperty($options, 'defaultUrlParams');
368 47
        if (isset($options['prefix'])) {
369 45
            $this->setPrefix($options['prefix']);
370 45
        }
371 47
        $this->setupProperty($options, 'debug');
372 47
        $this->updateApiURL();
373 47
    }
374
375
    /**
376
     * Set up one of properties
377
     *
378
     * @param array  $options  array of given properties
379
     * @param string $name     name of property to process
380
     * @param string $constant load default property value from constant
381
     */
382 24
    public function setupProperty($options, $name, $constant = null)
383
    {
384 24
        if (isset($options[$name])) {
385 22
            $this->$name = $options[$name];
386 22
        } else {
387 24
            if (is_null($this->$name) && !empty($constant) && defined($constant)) {
388 24
                $this->$name = constant($constant);
389 24
            }
390
        }
391 24
    }
392
393
    /**
394
     * Inicializace CURL
395
     */
396 70
    public function curlInit()
397
    {
398 70
        $this->curl = \curl_init(); // create curl resource
399 70
        curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); // return content as a string from curl_exec
400 70
        curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true); // follow redirects (compatibility for future changes in FlexiBee)
401 70
        curl_setopt($this->curl, CURLOPT_HTTPAUTH, true);       // HTTP authentication
402 70
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false); // FlexiBee by default uses Self-Signed certificates
403 70
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false);
404 70
        curl_setopt($this->curl, CURLOPT_VERBOSE, ($this->debug === true)); // For debugging
405 70
        curl_setopt($this->curl, CURLOPT_USERPWD,
406 70
            $this->user.':'.$this->password); // set username and password
407 70
    }
408
409
    /**
410
     * Zinicializuje objekt dle daných dat. Možné hodnoty:
411
     *
412
     *  * 234                              - interní číslo záznamu k načtení
413
     *  * code:LOPATA                      - kód záznamu
414
     *  * BAGR                             - kód záznamu k načtení
415
     *  * ['id'=>24,'nazev'=>'hoblík']     - pole hodnot k předvyplnění
416
     *  * 743.json?relations=adresa,vazby  - část url s parametry k načtení
417
     *
418
     * @param mixed $init číslo/"(code:)kód"/(část)URI záznamu k načtení | pole hodnot k předvyplnění
419
     */
420 44
    public function processInit($init)
421
    {
422 44
        if (is_integer($init)) {
423 42
            $this->loadFromFlexiBee($init);
424 44
        } elseif (is_array($init)) {
425 22
            $this->takeData($init);
426 22
        } elseif (preg_match('/\.(json|xml|csv)/', $init)) {
427
            $this->takeData($this->getFlexiData((($init[0] != '/') ? $this->getEvidenceURL($init)
0 ignored issues
show
Unused Code introduced by
The call to FlexiBeeRO::getEvidenceURL() has too many arguments starting with $init.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
428
                            : $init)));
429
        } else {
430
            $this->loadFromFlexiBee($init);
431
        }
432 44
    }
433
434
    /**
435
     * Set URL prefix
436
     *
437
     * @param string $prefix
438
     */
439 45
    public function setPrefix($prefix)
440
    {
441
        switch ($prefix) {
442 45
            case 'a': //Access
443 45
            case 'c': //Company
444 45
            case 'u': //User
445 45
            case 'g': //License Groups
446 45
            case 'admin':
447 45
            case 'status':
448 45
            case 'login-logout':
449 45
                $this->prefix = '/'.$prefix.'/';
450 45
                break;
451 23
            case null:
452 23
            case '':
453 23
            case '/':
454 23
                $this->prefix = '';
455 23
                break;
456 23
            default:
457 23
                throw new \Exception(sprintf('Unknown prefix %s', $prefix));
458 23
        }
459 45
    }
460
461
    /**
462
     * Set communication format.
463
     * One of html|xml|json|csv|dbf|xls|isdoc|isdocx|edi|pdf|pdf|vcf|ical
464
     *
465
     * @param string $format
466
     * @return boolen format is availble
467
     */
468 23
    public function setFormat($format)
469
    {
470 23
        $result = true;
471 23
        if (($this->debug === true) && !empty($this->evidence) && isset(Formats::$$this->evidence)) {
472
            if (array_key_exists($format, array_flip(Formats::$$this->evidence))
473
                === false) {
474
                $result = false;
475
            }
476
        }
477 23
        if ($result === true) {
478 23
            $this->format = $format;
479 23
            $this->updateApiURL();
480 23
        }
481 23
        return $result;
482
    }
483
484
    /**
485
     * Nastaví Evidenci pro Komunikaci.
486
     * Set evidence for communication
487
     *
488
     * @param string $evidence evidence pathName to use
489
     * @return boolean evidence switching status
490
     */
491 45
    public function setEvidence($evidence)
492
    {
493 45
        switch ($this->prefix) {
494 45
            case '/c/':
495 44
                if (array_key_exists($evidence, EvidenceList::$name)) {
496 41
                    $this->evidence = $evidence;
497 41
                    $result         = true;
498 41
                } else {
499 23
                    throw new \Exception(sprintf('Try to set unsupported evidence %s',
500 23
                        $evidence));
501
                }
502 41
                break;
503 4
            default:
504 4
                $this->evidence = $evidence;
505 4
                $result         = true;
506 4
                break;
507 45
        }
508 45
        $this->updateApiURL();
509 45
        return $result;
510
    }
511
512
    /**
513
     * Vrací právě používanou evidenci pro komunikaci
514
     * Obtain current used evidence
515
     *
516
     * @return string
517
     */
518 47
    public function getEvidence()
519
    {
520 47
        return $this->evidence;
521
    }
522
523
    /**
524
     * Set used company.
525
     * Nastaví Firmu.
526
     *
527
     * @param string $company
528
     */
529 23
    public function setCompany($company)
530
    {
531 23
        $this->company = $company;
532 23
    }
533
534
    /**
535
     * Obtain company now used
536
     * Vrací právě používanou firmu
537
     *
538
     * @return string
539
     */
540 23
    public function getCompany()
541
    {
542 23
        return $this->company;
543
    }
544
545
    /**
546
     * Vrací název evidence použité v odpovědích z FlexiBee
547
     *
548
     * @return string
549
     */
550 37
    public function getResponseEvidence()
551
    {
552 37
        switch ($this->evidence) {
553 37
            case 'c':
554
                $evidence = 'company';
555
                break;
556 37
            case 'evidence-list':
557 1
                $evidence = 'evidence';
558 1
                break;
559 36
            default:
560 36
                $evidence = $this->getEvidence();
561 36
                break;
562 37
        }
563 37
        return $evidence;
564
    }
565
566
    /**
567
     * Převede rekurzivně Objekt na pole.
568
     *
569
     * @param object|array $object
570
     *
571
     * @return array
572
     */
573 23
    public static function object2array($object)
574
    {
575 23
        $result = null;
576 23
        if (is_object($object)) {
577 23
            $objectData = get_object_vars($object);
578 23
            if (is_array($objectData) && count($objectData)) {
579 23
                $result = array_map('self::object2array', $objectData);
580 23
            }
581 23
        } else {
582 23
            if (is_array($object)) {
583 23
                foreach ($object as $item => $value) {
584 23
                    $result[$item] = self::object2array($value);
585 23
                }
586 23
            } else {
587 23
                $result = $object;
588
            }
589
        }
590
591 23
        return $result;
592
    }
593
594
    /**
595
     * Převede rekurzivně v poli všechny objekty na jejich identifikátory.
596
     *
597
     * @param object|array $object
598
     *
599
     * @return array
600
     */
601 23
    public static function objectToID($object)
602
    {
603 23
        $resultID = null;
604 23
        if (is_object($object)) {
605 23
            $resultID = $object->__toString();
606 23
        } else {
607 23
            if (is_array($object)) {
608 23
                foreach ($object as $item => $value) {
609 23
                    $resultID[$item] = self::objectToID($value);
610 23
                }
611 23
            } else { //String
612 23
                $resultID = $object;
613
            }
614
        }
615
616 23
        return $resultID;
617
    }
618
619
    /**
620
     * Return basic URL for used Evidence
621
     *
622
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Sestavování URL
623
     *
624
     * @return string Evidence URL
625
     */
626 45
    public function getEvidenceURL()
627
    {
628 45
        $evidenceUrl = $this->url.$this->prefix.$this->company;
629 45
        $evidence    = $this->getEvidence();
630 45
        if (!empty($evidence)) {
631 43
            $evidenceUrl .= '/'.$evidence;
632 43
        }
633 45
        return $evidenceUrl;
634
    }
635
636
    /**
637
     * Add suffix to Evidence URL
638
     *
639
     * @param string $urlSuffix
640
     *
641
     * @return string
642
     */
643 23
    public function evidenceUrlWithSuffix($urlSuffix)
644
    {
645 23
        $evidenceUrl = $this->getEvidenceUrl();
646 23
        if (!empty($urlSuffix)) {
647 23
            if (($urlSuffix[0] != '/') && ($urlSuffix[0] != ';') && ($urlSuffix[0]
648 23
                != '?')) {
649 23
                $evidenceUrl .= '/';
650 23
            }
651 23
            $evidenceUrl .= $urlSuffix;
652 23
        }
653 23
        return $evidenceUrl;
654
    }
655
656
    /**
657
     * Update $this->apiURL
658
     */
659 24
    public function updateApiURL()
660
    {
661 24
        $this->apiURL = $this->getEvidenceURL();
662 24
        $id           = $this->__toString();
663 24
        if (!empty($id)) {
664 13
            $this->apiURL .= '/'.urlencode($id);
665 13
        }
666 24
        $this->apiURL .= '.'.$this->format;
667 24
    }
668
669
    /**
670
     * Funkce, která provede I/O operaci a vyhodnotí výsledek.
671
     *
672
     * @param string $urlSuffix část URL za identifikátorem firmy.
673
     * @param string $method    HTTP/REST metoda
674
     * @param string $format    Requested format
675
     * @return array|boolean Výsledek operace
676
     */
677 42
    public function performRequest($urlSuffix = null, $method = 'GET',
678
                                   $format = null)
679
    {
680 42
        $this->rowCount = null;
681
682 42
        if (preg_match('/^http/', $urlSuffix)) {
683 22
            $url = $urlSuffix;
684 42
        } elseif (strlen($urlSuffix) && ($urlSuffix[0] == '/')) {
685 1
            $url = $this->url.$urlSuffix;
686 1
        } else {
687 19
            $url = $this->evidenceUrlWithSuffix($urlSuffix);
688
        }
689
690 42
        $responseCode = $this->doCurlRequest($url, $method, $format);
691
692 42
        return $this->parseResponse($this->rawResponseToArray($this->lastCurlResponse,
0 ignored issues
show
Bug introduced by
It seems like $this->rawResponseToArra... $this->responseFormat) targeting FlexiPeeHP\FlexiBeeRO::rawResponseToArray() can also be of type string; however, FlexiPeeHP\FlexiBeeRO::parseResponse() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
693 42
                    $this->responseFormat), $responseCode);
694
    }
695
696
    /**
697
     * Parse Raw FlexiBee response in several formats
698
     *
699
     * @param string $responseRaw raw response body
700
     * @param string $format      Raw Response format json|xml|etc
701
     *
702
     * @return array
703
     */
704 23
    public function rawResponseToArray($responseRaw, $format)
705
    {
706
        switch ($format) {
707 23
            case 'json':
708 23
                $responseDecoded = $this->rawJsonToArray($responseRaw);
709 23
                break;
710
            case 'xml':
711
                $responseDecoded = $this->rawXmlToArray($this->lastCurlResponse);
712
                break;
713
            case 'txt':
714
            default:
715
                $responseDecoded = $this->lastCurlResponse;
716
                break;
717
        }
718 23
        return $responseDecoded;
719
    }
720
721
    /**
722
     * Convert FlexiBee Response JSON to Array
723
     *
724
     * @param string $rawJson
725
     * 
726
     * @return array
727
     */
728 23
    public function rawJsonToArray($rawJson)
729
    {
730 23
        $responseDecoded = json_decode($rawJson, true, 10);
731 23
        $decodeError     = json_last_error_msg();
732 23
        if ($decodeError == 'No error') {
733 23
            if (array_key_exists($this->nameSpace, $responseDecoded)) {
734 21
                $responseDecoded = $responseDecoded[$this->nameSpace];
735 21
            }
736 23
        } else {
737
            $this->addStatusMessage('JSON Decoder: '.$decodeError, 'error');
738
            $this->addStatusMessage($rawJson, 'debug');
739
        }
740 23
        return $responseDecoded;
741
    }
742
743
    /**
744
     * Convert FlexiBee Response XML to Array
745
     *
746
     * @param string $rawXML
747
     *
748
     * @return array
749
     */
750
    public function rawXmlToArray($rawXML)
751
    {
752
        return self::xml2array($rawXML);
753
    }
754
755
    /**
756
     * Parse Response array
757
     *
758
     * @param array $responseDecoded
759
     * @param int $responseCode Request Response Code
760
     *
761
     * @return array main data part of response
762
     */
763 23
    public function parseResponse($responseDecoded, $responseCode)
764
    {
765 23
        $response = null;
766
        switch ($responseCode) {
767 23
            case 201: //Success Write
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...
768
                if (isset($responseDecoded[$this->resultField][0]['id'])) {
769
                    $this->lastInsertedID = $responseDecoded[$this->resultField][0]['id'];
770
                    $this->setMyKey($this->lastInsertedID);
771
                    $this->apiURL         = $this->getEvidenceURL().'/'.$this->lastInsertedID;
772
                } else {
773
                    $this->lastInsertedID = null;
774
                }
775 23
            case 200: //Success Read
776 14
                $response         = $this->lastResult = $this->unifyResponseFormat($responseDecoded);
777 14
                if (isset($responseDecoded['@rowCount'])) {
778
                    $this->rowCount = (int) $responseDecoded['@rowCount'];
779
                }
780 14
                if (isset($responseDecoded['@globalVersion'])) {
781
                    $this->globalVersion = (int) $responseDecoded['@globalVersion'];
782
                }
783 14
                break;
784
785 9
            case 500: // Internal Server Error
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...
786
                if ($this->debug === true) {
787
                    $this->error500Reporter($responseDecoded);
788
                }
789 9
            case 404: // Page not found
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...
790 8
                if ($this->ignoreNotFound === true) {
791
                    break;
792
                }
793 9
            case 400: //Bad Request parameters
794 9
            default: //Something goes wrong
795 9
                $this->addStatusMessage($this->lastResponseCode.': '.$this->curlInfo['url'],
796 9
                    'warning');
797 9
                if (is_array($responseDecoded)) {
798 9
                    $this->parseError($responseDecoded);
799 9
                }
800 9
                $this->logResult($responseDecoded, $this->curlInfo['url']);
801 9
                break;
802
        }
803 23
        return $response;
804
    }
805
806
    /**
807
     * Parse error message response
808
     *
809
     * @param array $responseDecoded
810
     * @return int number of errors processed
811
     */
812 9
    public function parseError(array $responseDecoded)
813
    {
814 9
        if (array_key_exists('results', $responseDecoded)) {
815
            $this->errors = $responseDecoded['results'][0]['errors'];
816
        } else {
817 9
            if (array_key_exists('message', $responseDecoded)) {
818 8
                $this->errors = [['message' => $responseDecoded['message']]];
819 8
            }
820
        }
821 9
        return count($this->errors);
822
    }
823
824
    /**
825
     * Vykonej HTTP požadavek
826
     *
827
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Sestavování URL
828
     * @param string $url    URL požadavku
829
     * @param string $method HTTP Method GET|POST|PUT|OPTIONS|DELETE
830
     * @param string $format požadovaný formát komunikace
831
     * @return int HTTP Response CODE
832
     */
833 23
    public function doCurlRequest($url, $method, $format = null)
834
    {
835 23
        if (is_null($format)) {
836 23
            $format = $this->format;
837 23
        }
838 23
        curl_setopt($this->curl, CURLOPT_URL, $url);
839
// Nastavení samotné operace
840 23
        curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, strtoupper($method));
841
//Vždy nastavíme byť i prázná postdata jako ochranu před chybou 411
842 23
        curl_setopt($this->curl, CURLOPT_POSTFIELDS, $this->postFields);
843
844 23
        $httpHeaders = $this->defaultHttpHeaders;
845
846 23
        $formats = Formats::bySuffix();
847
848 23
        if (!isset($httpHeaders['Accept'])) {
849 23
            $httpHeaders['Accept'] = $formats[$format]['content-type'];
850 23
        }
851 23
        if (!isset($httpHeaders['Content-Type'])) {
852 23
            $httpHeaders['Content-Type'] = $formats[$format]['content-type'];
853 23
        }
854 23
        $httpHeadersFinal = [];
855 23
        foreach ($httpHeaders as $key => $value) {
856 23
            if (($key == 'User-Agent') && ($value == 'FlexiPeeHP')) {
857 23
                $value .= ' v'.self::$libVersion;
858 23
            }
859 23
            $httpHeadersFinal[] = $key.': '.$value;
860 23
        }
861
862 23
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, $httpHeadersFinal);
863
864
// Proveď samotnou operaci
865 23
        $this->lastCurlResponse            = curl_exec($this->curl);
866 23
        $this->curlInfo                    = curl_getinfo($this->curl);
867 23
        $this->curlInfo['when']            = microtime();
868 23
        $this->curlInfo['request_headers'] = $httpHeadersFinal;
869 23
        $this->responseFormat              = isset($this->curlInfo['content_type'])
870 23
                ? Formats::contentTypeToSuffix($this->curlInfo['content_type']) : 'txt';
871 23
        $this->lastResponseCode            = $this->curlInfo['http_code'];
872 23
        $this->lastCurlError               = curl_error($this->curl);
873 23
        if (strlen($this->lastCurlError)) {
874
            $this->addStatusMessage(sprintf('Curl Error (HTTP %d): %s',
875
                    $this->lastResponseCode, $this->lastCurlError), 'error');
876
        }
877
878 23
        if ($this->debug === true) {
879
            $this->saveDebugFiles();
880
        }
881
882 23
        return $this->lastResponseCode;
883
    }
884
885
    /**
886
     * Nastaví druh prováděné akce.
887
     *
888
     * @link https://demo.flexibee.eu/devdoc/actions Provádění akcí
889
     * @param string $action
890
     * @return boolean
891
     */
892 15
    public function setAction($action)
893
    {
894 15
        $result           = false;
895 15
        $actionsAvailable = $this->getActionsInfo();
896 15
        if (is_array($actionsAvailable) && array_key_exists($action,
897 15
                $actionsAvailable)) {
898 15
            $this->action = $action;
899 15
            $result       = true;
900 15
        }
901 15
        return $result;
902
    }
903
904
    /**
905
     * Convert XML to array.
906
     *
907
     * @param string $xml
908
     *
909
     * @return array
910
     */
911 23
    public static function xml2array($xml)
912
    {
913 23
        $arr = [];
914 23
        if (!empty($xml)) {
915 23
            if (is_string($xml)) {
916 23
                $xml = simplexml_load_string($xml);
917 23
            }
918
919 23
            foreach ($xml->children() as $r) {
920 23
                if (count($r->children()) == 0) {
921 23
                    $arr[$r->getName()] = strval($r);
922 23
                } else {
923 23
                    $arr[$r->getName()][] = self::xml2array($r);
924
                }
925 23
            }
926 23
        }
927 23
        return $arr;
928
    }
929
930
    /**
931
     * Odpojení od FlexiBee.
932
     */
933 23
    public function disconnect()
934
    {
935 23
        if (is_resource($this->curl)) {
936 23
            curl_close($this->curl);
937 23
        }
938 23
        $this->curl = null;
939 23
    }
940
941
    /**
942
     * Disconnect CURL befere pass away
943
     */
944 23
    public function __destruct()
945
    {
946 23
        $this->disconnect();
947 23
    }
948
949
    /**
950
     * Načte řádek dat z FlexiBee.
951
     *
952
     * @param int $recordID id požadovaného záznamu
953
     *
954
     * @return array
955
     */
956 23
    public function getFlexiRow($recordID)
957
    {
958 23
        $record   = null;
959 23
        $response = $this->performRequest($this->evidence.'/'.$recordID.'.json');
960 23
        if (isset($response[$this->evidence])) {
961
            $record = $response[$this->evidence][0];
962
        }
963
964 23
        return $record;
965
    }
966
967
    /**
968
     * Oddělí z pole podmínek ty jenž patří za ? v URL požadavku
969
     *
970
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Sestavování URL
971
     * @param array $conditions pole podmínek   - rendrují se do ()
972
     * @param array $urlParams  pole parametrů  - rendrují za ?
973
     */
974
    public function extractUrlParams(&$conditions, &$urlParams)
975
    {
976
        foreach ($this->urlParams as $urlParam) {
977
            if (isset($conditions[$urlParam])) {
978
                \Ease\Sand::divDataArray($conditions, $urlParams, $urlParam);
979
            }
980
        }
981
    }
982
983
    /**
984
     * convert unicode to entities
985
     *
986
     * @param string $urlRaw
987
     * @return string
988
     */
989
    public static function urlEncode($urlRaw)
990
    {
991
        return str_replace(['%27'], ["'"], rawurlencode($urlRaw));
992
    }
993
994
    /**
995
     * Načte data z FlexiBee.
996
     *
997
     * @param string $suffix     dotaz
998
     * @param string|array $conditions Volitelný filtrovací výraz
999
     *
1000
     * @return array Data obtained
1001
     */
1002 41
    public function getFlexiData($suffix = null, $conditions = null)
1003
    {
1004 41
        $finalUrl  = '';
1005 41
        $urlParams = $this->defaultUrlParams;
1006
1007 41
        if (!is_null($conditions)) {
1008 18
            if (is_array($conditions)) {
1009 16
                $this->extractUrlParams($conditions, $urlParams);
1010 16
                $conditions = $this->flexiUrl($conditions);
1011 16
            }
1012
1013 18
            if (strlen($conditions) && ($conditions[0] != '/')) {
1014 15
                $conditions = '('.self::urlEncode($conditions).')';
1015 15
            }
1016 18
        }
1017
1018 41
        if (strlen($suffix)) {
1019 22
            if (preg_match('/^http/', $suffix) || ($suffix[0] == '/') || is_numeric($suffix)) {
1020 22
                $finalUrl = $suffix;
1021 22
            } else {
1022
                if (preg_match('/^(code|ext):(.*)/', $suffix, $matches)) {
1023
                    $finalUrl = $matches[1].':'.rawurlencode($matches[2]);
1024
                }
1025
            }
1026 22
        }
1027
1028 41
        $finalUrl .= $conditions;
1029
1030 41
        if (count($urlParams)) {
1031 41
            if (strstr($finalUrl, '?')) {
1032
                $finalUrl .= '&';
1033
            } else {
1034 41
                $finalUrl .= '?';
1035
            }
1036 41
            $finalUrl .= http_build_query($urlParams, null, '&',
1037 41
                PHP_QUERY_RFC3986);
1038 41
        }
1039
1040 41
        $transactions = $this->performRequest($finalUrl, 'GET');
1041
1042 41
        $responseEvidence = $this->getResponseEvidence();
1043 41
        if (is_array($transactions) && array_key_exists($responseEvidence,
1044 41
                $transactions)) {
1045 30
            $result = $transactions[$responseEvidence];
1046 30
            if ((count($result) == 1) && (count(current($result)) == 0 )) {
1047
                $result = null; // Response is empty Array
1048
            }
1049 30
        } else {
1050 11
            $result = $transactions;
1051
        }
1052
1053 41
        return $result;
1054
    }
1055
1056
    /**
1057
     * Načte záznam z FlexiBee a uloží v sobě jeho data
1058
     * Read FlexiBee record and store it inside od object
1059
     *
1060
     * @param int $id ID or conditions
1061
     *
1062
     * @return int počet načtených položek
1063
     */
1064 45
    public function loadFromFlexiBee($id = null)
1065
    {
1066 45
        $data = [];
1067 45
        if (is_null($id)) {
1068 23
            $id = $this->getMyKey();
1069 23
        }
1070 45
        if (is_array($id)) {
1071
            $id = rawurlencode('('.self::flexiUrl($id).')');
1072
        }
1073
1074 45
        if (preg_match('/^code/', $id)) {
1075
            $id = self::code(rawurlencode(self::uncode($id)));
1076
        }
1077
1078 45
        $flexidata    = $this->getFlexiData($this->getEvidenceUrl().'/'.$id);
1079 45
        $this->apiURL = $this->curlInfo['url'];
1080 45
        if (is_array($flexidata) && (count($flexidata) == 1)) {
1081 22
            $data = current($flexidata);
1082 22
        }
1083 45
        return $this->takeData($data);
1084
    }
1085
1086
    /**
1087
     * Převede data do Json formátu pro FlexiBee.
1088
     * Convert data to FlexiBee like Json format
1089
     *
1090
     * @param array $data
1091
     *
1092
     * @return string
1093
     */
1094 15
    public function jsonizeData($data)
1095
    {
1096
        $dataToJsonize = [
1097 15
            $this->nameSpace => [
1098 15
                '@version' => $this->protoVersion,
1099 15
                $this->evidence => $this->objectToID($data),
1100 15
            ],
1101 15
        ];
1102
1103 15 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...
1104 15
            $dataToJsonize[$this->nameSpace][$this->evidence.'@action'] = $this->action;
1105 15
            $this->action                                               = null;
1106 15
        }
1107
1108 15 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...
1109
            $dataToJsonize[$this->nameSpace][$this->evidence.'@filter'] = $this->filter;
1110
        }
1111
1112 15
        return json_encode($dataToJsonize);
1113
    }
1114
1115
    /**
1116
     * Test if given record ID exists in FlexiBee.
1117
     *
1118
     * @param boolean $identifer presence state
1119
     */
1120 15
    public function idExists($identifer = null)
1121
    {
1122 15
        if (is_null($identifer)) {
1123 15
            $identifer = $this->getMyKey();
1124 15
        }
1125 15
        $this->getFlexiData(null,
1126
            [
1127 15
            'detail' => 'custom:'.$this->getmyKeyColumn(),
1128 15
            $this->getmyKeyColumn() => $identifer
1129 15
        ]);
1130
1131 15
        return $this->lastResponseCode == 200;
1132
    }
1133
1134
    /**
1135
     * Test if given record exists in FlexiBee.
1136
     *
1137
     * @param array $data
1138
     * @return boolean Record presence status
1139
     */
1140 16
    public function recordExists($data = [])
1141
    {
1142
1143 16
        if (empty($data)) {
1144 16
            $data = $this->getData();
1145 16
        }
1146
1147 16
        $res = $this->getColumnsFromFlexibee([$this->myKeyColumn],
1148 16
            [self::flexiUrl($data)]);
1149
1150 16
        if (!count($res) || (isset($res['success']) && ($res['success'] == 'false'))
1151 16
            || !count($res[0])) {
1152 16
            $found = false;
1153 16
        } else {
1154 15
            $found = true;
1155
        }
1156 16
        return $found;
1157
    }
1158
1159
    /**
1160
     * Vrací z FlexiBee sloupečky podle podmínek.
1161
     *
1162
     * @param array|int|string $conditions pole podmínek nebo ID záznamu
1163
     * @param string           $indexBy    klice vysledku naplnit hodnotou ze
1164
     *                                     sloupečku
1165
     * @return array
1166
     */
1167
    public function getAllFromFlexibee($conditions = null, $indexBy = null)
1168
    {
1169
        if (is_int($conditions)) {
1170
            $conditions = [$this->getmyKeyColumn() => $conditions];
1171
        }
1172
1173
        $flexiData = $this->getFlexiData('', $conditions);
1174
1175
        if (!is_null($indexBy)) {
1176
            $flexiData = $this->reindexArrayBy($flexiData);
1177
        }
1178
1179
        return $flexiData;
1180
    }
1181
1182
    /**
1183
     * Vrací z FlexiBee sloupečky podle podmínek.
1184
     *
1185
     * @param string[] $columnsList seznam položek
1186
     * @param array    $conditions  pole podmínek nebo ID záznamu
1187
     * @param string   $indexBy     Sloupeček podle kterého indexovat záznamy
1188
     *
1189
     * @return array
1190
     */
1191 15
    public function getColumnsFromFlexibee($columnsList, $conditions = [],
1192
                                           $indexBy = null)
1193
    {
1194 15
        $detail = 'full';
1195 15
        switch (gettype($columnsList)) {
1196 15
            case 'integer': //Record ID
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...
1197
                $conditions = [$this->getmyKeyColumn() => $conditions];
1198 15
            case 'array': //Few Conditions
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...
1199 15
                if (!is_null($indexBy) && !array_key_exists($indexBy,
1200 15
                        $columnsList)) {
1201 15
                    $columnsList[] = $indexBy;
1202 15
                }
1203 15
                $columns = implode(',', array_unique($columnsList));
1204 15
                $detail  = 'custom:'.$columns;
1205 15
            default:
1206
                switch ($columnsList) {
1207 15
                    case 'id':
1208
                        $detail = 'id';
1209
                        break;
1210 15
                    case 'summary':
1211
                        $detail = 'summary';
1212
                        break;
1213 15
                    default:
1214 15
                        break;
1215 15
                }
1216 15
                break;
1217 15
        }
1218
1219 15
        $conditions['detail'] = $detail;
1220
1221 15
        $flexiData = $this->getFlexiData(null, $conditions);
1222
1223 15
        if (!is_null($indexBy) && count($flexiData) && count(current($flexiData))) {
1224 15
            $flexiData = $this->reindexArrayBy($flexiData, $indexBy);
1225 15
        }
1226
1227 15
        return $flexiData;
1228
    }
1229
1230
    /**
1231
     * Vrací kód záznamu.
1232
     * Obtain record CODE
1233
     *
1234
     * @param mixed $data
1235
     *
1236
     * @return string
1237
     */
1238 23
    public function getKod($data = null, $unique = true)
1239
    {
1240 23
        $kod = null;
1241
1242 23
        if (is_null($data)) {
1243 23
            $data = $this->getData();
1244 23
        }
1245
1246 23
        if (is_string($data)) {
1247 23
            $data = [$this->nameColumn => $data];
1248 23
        }
1249
1250 23
        if (isset($data['kod'])) {
1251 23
            $kod = $data['kod'];
1252 23
        } else {
1253 23
            if (isset($data[$this->nameColumn])) {
1254 23
                $kod = preg_replace('/[^a-zA-Z0-9]/', '',
1255 23
                    \Ease\Sand::rip($data[$this->nameColumn]));
1256 23
            } else {
1257 23
                if (isset($data[$this->myKeyColumn])) {
1258 23
                    $kod = \Ease\Sand::rip($data[$this->myKeyColumn]);
1259 23
                }
1260
            }
1261
        }
1262
1263 23
        if (!strlen($kod)) {
1264 23
            $kod = 'NOTSET';
1265 23
        }
1266
1267 23
        if (strlen($kod) > 18) {
1268 23
            $kodfinal = strtoupper(substr($kod, 0, 18));
1269 23
        } else {
1270 23
            $kodfinal = strtoupper($kod);
1271
        }
1272
1273 23
        if ($unique) {
1274 23
            $counter = 0;
1275 23
            if (count($this->codes)) {
1276 23
                foreach ($this->codes as $codesearch => $keystring) {
1277 23
                    if (strstr($codesearch, $kodfinal)) {
1278 23
                        ++$counter;
1279 23
                    }
1280 23
                }
1281 23
            }
1282 23
            if ($counter) {
1283 23
                $kodfinal = $kodfinal.$counter;
1284 23
            }
1285
1286 23
            $this->codes[$kodfinal] = $kod;
1287 23
        }
1288
1289 23
        return self::code($kodfinal);
1290
    }
1291
1292
    /**
1293
     * Write Operation Result.
1294
     *
1295
     * @param array  $resultData
1296
     * @param string $url        URL
1297
     * @return boolean Log save success
1298
     */
1299 32
    public function logResult($resultData = null, $url = null)
1300
    {
1301 32
        $logResult = false;
1302 32
        if (isset($resultData['success']) && ($resultData['success'] == 'false')) {
1303 31
            if (isset($resultData['message'])) {
1304 8
                $this->addStatusMessage($resultData['message'], 'warning');
1305 8
            }
1306 31
            $this->addStatusMessage('Error '.$this->lastResponseCode.': '.urldecode($url),
1307 31
                'warning');
1308 31
            unset($url);
1309 31
        }
1310 32
        if (is_null($resultData)) {
1311
            $resultData = $this->lastResult;
1312
        }
1313 32
        if (isset($url)) {
1314 24
            $this->logger->addStatusMessage($this->lastResponseCode.':'.urldecode($url));
1315 24
        }
1316
1317 32
        if (isset($resultData['results'])) {
1318 23
            if ($resultData['success'] == 'false') {
1319 23
                $status = 'error';
1320 23
            } else {
1321 23
                $status = 'success';
1322
            }
1323 23
            foreach ($resultData['results'] as $result) {
1324 23
                if (isset($result['request-id'])) {
1325 23
                    $rid = $result['request-id'];
1326 23
                } else {
1327 23
                    $rid = '';
1328
                }
1329 23
                if (isset($result['errors'])) {
1330 23
                    foreach ($result['errors'] as $error) {
1331 23
                        $message = $error['message'];
1332 23
                        if (isset($error['for'])) {
1333
                            $message .= ' for: '.$error['for'];
1334
                        }
1335 23
                        if (isset($error['value'])) {
1336
                            $message .= ' value:'.$error['value'];
1337
                        }
1338 23
                        if (isset($error['code'])) {
1339
                            $message .= ' code:'.$error['code'];
1340
                        }
1341 23
                        $this->addStatusMessage($rid.': '.$message, $status);
1342 23
                    }
1343 23
                }
1344 23
            }
1345 23
        }
1346 32
        return $logResult;
1347
    }
1348
1349
    /**
1350
     * Save RAW Curl Request & Response to files in Temp directory
1351
     */
1352
    public function saveDebugFiles()
1353
    {
1354
        $tmpdir   = sys_get_temp_dir();
1355
        $fname    = $this->evidence.'-'.$this->curlInfo['when'].'.'.$this->format;
1356
        $reqname  = $tmpdir.'/request-'.$fname;
1357
        $respname = $tmpdir.'/response-'.$fname;
1358
        file_put_contents($reqname, $this->postFields);
1359
        file_put_contents($respname, $this->lastCurlResponse);
1360
    }
1361
1362
    /**
1363
     * Připraví data pro odeslání do FlexiBee
1364
     *
1365
     * @param string $data
1366
     */
1367
    public function setPostFields($data)
1368
    {
1369
        $this->postFields = $data;
1370
    }
1371
1372
    /**
1373
     * Generuje fragment url pro filtrování.
1374
     *
1375
     * @see https://www.flexibee.eu/api/dokumentace/ref/filters
1376
     *
1377
     * @param array  $data
1378
     * @param string $joiner default and/or
1379
     * @param string $defop  default operator
1380
     *
1381
     * @return string
1382
     */
1383 23
    public static function flexiUrl(array $data, $joiner = 'and', $defop = 'eq')
1384
    {
1385 23
        $parts = [];
1386
1387 23
        foreach ($data as $column => $value) {
1388 23
            if (!is_numeric($column)) {
1389 23
                if (is_integer($data[$column]) || is_float($data[$column])) {
1390 23
                    $parts[$column] = $column.' eq \''.$data[$column].'\'';
1391 23
                } elseif (is_bool($data[$column])) {
1392 23
                    $parts[$column] = $data[$column] ? $column.' eq true' : $column.' eq false';
1393 23
                } elseif (is_null($data[$column])) {
1394 23
                    $parts[$column] = $column." is null";
1395 23
                } else {
1396
                    switch ($value) {
1397 23
                        case '!null':
1398 23
                            $parts[$column] = $column." is not null";
1399 23
                            break;
1400 23
                        case 'is empty':
1401 23
                        case 'is not empty':
1402
                            $parts[$column] = $column.' '.$value;
1403
                            break;
1404 23
                        default:
1405 23
                            if ($column == 'stitky') {
1406
                                $parts[$column] = $column."='".self::code($data[$column])."'";
1407
                            } else {
1408 23
                                $parts[$column] = $column." $defop '".$data[$column]."'";
1409
                            }
1410 23
                            break;
1411 23
                    }
1412
                }
1413 23
            } else {
1414
                $parts[] = $value;
1415
            }
1416 23
        }
1417 23
        return implode(' '.$joiner.' ', $parts);
1418
    }
1419
1420
    /**
1421
     * Obtain record/object identificator code: or id:
1422
     * Vrací identifikátor objektu code: nebo id:
1423
     *
1424
     * @link https://demo.flexibee.eu/devdoc/identifiers Identifikátory záznamů
1425
     * @return string|int indentifikátor záznamu reprezentovaného objektem
1426
     */
1427 47
    public function getRecordID()
1428
    {
1429 47
        $myCode = $this->getDataValue('kod');
1430 47
        if ($myCode) {
1431 33
            $id = self::code($myCode);
1432 33
        } else {
1433 47
            $id = $this->getDataValue('id');
1434 47
            if (($this->debug === true) && is_null($id)) {
1435 9
                $this->addToLog('Object Data does not contain code: or id: cannot match with statement!',
1436 9
                    'warning');
1437 9
            }
1438
        }
1439 47
        return is_numeric($id) ? intval($id) : strval($id);
1440
    }
1441
1442
    /**
1443
     * Obtain record/object identificator code: or id:
1444
     * Vrací identifikátor objektu code: nebo id:
1445
     *
1446
     * @link https://demo.flexibee.eu/devdoc/identifiers Identifikátory záznamů
1447
     * @return string indentifikátor záznamu reprezentovaného objektem
1448
     */
1449 47
    public function __toString()
1450
    {
1451 47
        return strval($this->getRecordID());
1452
    }
1453
1454
    /**
1455
     * Gives you FlexiPeeHP class name for Given Evidence
1456
     *
1457
     * @param string $evidence
1458
     * @return string Class name
1459
     */
1460 23
    public static function evidenceToClassName($evidence)
1461
    {
1462 23
        return str_replace(' ', '', ucwords(str_replace('-', ' ', $evidence)));
1463
    }
1464
1465
    /**
1466
     * Obtain ID of first record in evidence
1467
     *
1468
     * @return string|null id or null if no records
1469
     */
1470 15
    public function getFirstRecordID()
1471
    {
1472 15
        $firstID    = null;
1473 15
        $firstIdRaw = $this->getColumnsFromFlexibee(['id'],
1474 15
            ['limit' => 1, 'order' => 'id'], 'id');
1475 15
        if (count($firstIdRaw)) {
1476 15
            $firstID = (int) current($firstIdRaw)['id'];
1477 15
        }
1478 15
        return $firstID;
1479
    }
1480
1481
    /**
1482
     * Vrací hodnotu daného externího ID
1483
     *
1484
     * @param string $want Which ? If empty,you obtain the first one.
1485
     * @return string
1486
     */
1487 23
    public function getExternalID($want = null)
1488
    {
1489 23
        $extid = null;
1490 23
        $ids   = $this->getDataValue('external-ids');
1491 23
        if (is_null($want)) {
1492 23
            if (count($ids)) {
1493 23
                $extid = current($ids);
1494 23
            }
1495 23
        } else {
1496 23
            if (!is_null($ids) && is_array($ids)) {
1497 23
                foreach ($ids as $id) {
1498 23
                    if (strstr($id, 'ext:'.$want)) {
1499 23
                        $extid = str_replace('ext:'.$want.':', '', $id);
1500 23
                    }
1501 23
                }
1502 23
            }
1503
        }
1504 23
        return $extid;
1505
    }
1506
1507
    /**
1508
     * Obtain actual GlobalVersion
1509
     * Vrací aktuální globální verzi změn
1510
     *
1511
     * @link https://www.flexibee.eu/api/dokumentace/ref/changes-api#globalVersion Globální Verze
1512
     * @return type
1513
     */
1514 15
    public function getGlobalVersion()
1515
    {
1516 15
        $this->getFlexiData(null, ['add-global-version' => 'true', 'limit' => 1]);
1517
1518 15
        return $this->globalVersion;
1519
    }
1520
1521
    /**
1522
     * Obtain content type of last response
1523
     *
1524
     * @return string
1525
     */
1526 23
    public function getResponseFormat()
1527
    {
1528 23
        if (isset($this->curlInfo['content_type'])) {
1529 23
            $responseFormat = $this->curlInfo['content_type'];
1530 23
        } else {
1531
            $responseFormat = null;
1532
        }
1533 23
        return $responseFormat;
1534
    }
1535
1536
    /**
1537
     * Return the same response format for one and multiplete results
1538
     *
1539
     * @param array $responseBody
1540
     * @return array
1541
     */
1542 35
    public function unifyResponseFormat($responseBody)
1543
    {
1544 35
        if (!is_array($responseBody) || array_key_exists('message',
1545 35
                $responseBody)) { //Unifi response format
1546 22
            $response = $responseBody;
1547 22
        } else {
1548 35
            $evidence = $this->getResponseEvidence();
1549 35
            if (array_key_exists($evidence, $responseBody)) {
1550 35
                $response        = [];
1551 35
                $evidenceContent = $responseBody[$evidence];
1552 35
                if (array_key_exists(0, $evidenceContent)) {
1553 35
                    $response[$evidence] = $evidenceContent; //Multiplete Results
1554 35
                } else {
1555 22
                    $response[$evidence][0] = $evidenceContent; //One result
1556
                }
1557 35
            } else {
1558
                if (isset($responseBody['priloha'])) {
1559
                    $response = $responseBody['priloha'];
1560
                } else {
1561
                    if (array_key_exists('results', $responseBody)) {
1562
                        $response = $responseBody['results'];
1563
                    } else {
1564
                        $response = $responseBody;
1565
                    }
1566
                }
1567
            }
1568
        }
1569 35
        return $response;
1570
    }
1571
1572
    /**
1573
     * Obtain structure for current (or given) evidence
1574
     *
1575
     * @param string $evidence
1576
     * @return array Evidence structure
1577
     */
1578 23
    public function getColumnsInfo($evidence = null)
1579
    {
1580 23
        $columnsInfo = null;
1581 23
        $infoSource  = self::$infoDir.'/Properties.'.(empty($evidence) ? $this->getEvidence()
1582 23
                : $evidence).'.json';
1583 23
        if (file_exists($infoSource)) {
1584
            $columnsInfo = json_decode(file_get_contents($infoSource), true);
1585
        }
1586 23
        return $columnsInfo;
1587
    }
1588
1589
    /**
1590
     * Obtain actions for current (or given) evidence
1591
     *
1592
     * @param string $evidence
1593
     * @return array Evidence structure
1594
     */
1595 23
    public function getActionsInfo($evidence = null)
1596
    {
1597 23
        $actionsInfo = null;
1598 23
        if (is_null($evidence)) {
1599 23
            $evidence = $this->getEvidence();
1600 23
        }
1601 23
        $propsName = lcfirst(FlexiBeeRO::evidenceToClassName($evidence));
1602 23
        if (isset(\FlexiPeeHP\Actions::$$propsName)) {
1603 23
            $actionsInfo = Actions::$$propsName;
1604 23
        }
1605 23
        return $actionsInfo;
1606
    }
1607
1608
    /**
1609
     * Obtain relations for current (or given) evidence
1610
     *
1611
     * @param string $evidence
1612
     * @return array Evidence structure
1613
     */
1614 23
    public function getRelationsInfo($evidence = null)
1615
    {
1616 23
        $relationsInfo = null;
1617 23
        if (is_null($evidence)) {
1618 23
            $evidence = $this->getEvidence();
1619 23
        }
1620 23
        $propsName = lcfirst(FlexiBeeRO::evidenceToClassName($evidence));
1621 23
        if (isset(\FlexiPeeHP\Relations::$$propsName)) {
1622 13
            $relationsInfo = Relations::$$propsName;
1623 13
        }
1624 23
        return $relationsInfo;
1625
    }
1626
1627
    /**
1628
     * Obtain info for current (or given) evidence
1629
     *
1630
     * @param string $evidence
1631
     * @return array Evidence info
1632
     */
1633 15 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...
1634
    {
1635 15
        $evidencesInfo = null;
1636 15
        if (is_null($evidence)) {
1637 15
            $evidence = $this->getEvidence();
1638 15
        }
1639 15
        if (isset(EvidenceList::$evidences[$evidence])) {
1640 15
            $evidencesInfo = EvidenceList::$evidences[$evidence];
1641 15
        }
1642 15
        return $evidencesInfo;
1643
    }
1644
1645
    /**
1646
     * Obtain name for current (or given) evidence path
1647
     *
1648
     * @param string $evidence Evidence Path
1649
     * @return array Evidence info
1650
     */
1651 15 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...
1652
    {
1653 15
        $evidenceName = null;
1654 15
        if (is_null($evidence)) {
1655 15
            $evidence = $this->getEvidence();
1656 15
        }
1657 15
        if (isset(EvidenceList::$name[$evidence])) {
1658 15
            $evidenceName = EvidenceList::$name[$evidence];
1659 15
        }
1660 15
        return $evidenceName;
1661
    }
1662
1663
    /**
1664
     * Perform given action (if availble) on current evidence/record
1665
     * @url https://demo.flexibee.eu/devdoc/actions
1666
     *
1667
     * @param string $action one of evidence actions
1668
     * @param string $method ext|int External method call operation in URL.
1669
     *                               Internal add the @action element to request body
1670
     */
1671 23
    public function performAction($action, $method = 'ext')
1672
    {
1673 23
        $actionsAvailble = $this->getActionsInfo();
1674
1675 23
        if (is_array($actionsAvailble) && array_key_exists($action,
1676 23
                $actionsAvailble)) {
1677 15
            switch ($actionsAvailble[$action]['actionMakesSense']) {
1678 15
                case 'ONLY_WITH_INSTANCE_AND_NOT_IN_EDIT':
1679 15
                case 'ONLY_WITH_INSTANCE': //Add instance
1680 4
                    $urlSuffix = '/'.$this->__toString().'/'.$action.'.'.$this->format;
1681 4
                    break;
1682
1683 15
                default:
1684 15
                    $urlSuffix = '/'.$action;
1685 15
                    break;
1686 15
            }
1687
1688
            switch ($method) {
1689 15
                case 'int':
1690
                    $this->setAction($action);
1691
                    $this->setPostFields($this->jsonizeData($this->getData()));
1692
                    $result = $this->performRequest(null, 'POST');
1693
                    break;
1694
1695 15
                default:
1696 15
                    $result = $this->performRequest($this->evidenceUrlWithSuffix($urlSuffix),
1697 15
                        'GET');
1698 15
                    break;
1699 15
            }
1700 15
        } else {
1701 19
            throw new \Exception(sprintf(_('Unsupported action %s for evidence %s'),
1702 19
                $action, $this->getEvidence()));
1703
        }
1704
1705 15
        return $result;
1706
    }
1707
1708
    /**
1709
     * Save current object to file
1710
     *
1711
     * @param string $destfile path to file
1712
     */
1713 23
    public function saveResponseToFile($destfile)
1714
    {
1715 23
        if (strlen($this->lastCurlResponse)) {
1716 1
            $this->doCurlRequest($this->apiURL, 'GET', $this->format);
1717 1
        }
1718 23
        file_put_contents($destfile, $this->lastCurlResponse);
1719 23
    }
1720
1721
    /**
1722
     * Obtain established relations listing
1723
     *
1724
     * @return array Null or Relations
1725
     */
1726 4
    public function getVazby($id = null)
1727
    {
1728 4
        if (is_null($id)) {
1729 4
            $id = $this->getRecordID();
1730 4
        }
1731 4
        if (!empty($id)) {
1732 4
            $vazbyRaw = $this->getColumnsFromFlexibee(['vazby'],
1733 4
                ['relations' => 'vazby', 'id' => $id]);
1734 4
            $vazby    = array_key_exists('vazby', $vazbyRaw[0]) ? $vazbyRaw[0]['vazby']
1735 4
                    : null;
1736 4
        } else {
1737 4
            throw new \Exception(_('ID requied to get record relations '));
1738
        }
1739 4
        return $vazby;
1740
    }
1741
1742
    /**
1743
     * Gives You URL for Current Record in FlexiBee web interface
1744
     *
1745
     * @return string url
1746
     */
1747
    public function getFlexiBeeURL()
1748
    {
1749
        $parsed_url = parse_url(str_replace('.'.$this->format, '', $this->apiURL));
1750
        $scheme     = isset($parsed_url['scheme']) ? $parsed_url['scheme'].'://'
1751
                : '';
1752
        $host       = isset($parsed_url['host']) ? $parsed_url['host'] : '';
1753
        $port       = isset($parsed_url['port']) ? ':'.$parsed_url['port'] : '';
1754
        $user       = isset($parsed_url['user']) ? $parsed_url['user'] : '';
1755
        $pass       = isset($parsed_url['pass']) ? ':'.$parsed_url['pass'] : '';
1756
        $pass       = ($user || $pass) ? "$pass@" : '';
1757
        $path       = isset($parsed_url['path']) ? $parsed_url['path'] : '';
1758
        return $scheme.$user.$pass.$host.$port.$path;
1759
    }
1760
1761
    /**
1762
     * Set Record Key
1763
     *
1764
     * @param int|string $myKeyValue
1765
     * @return boolean
1766
     */
1767
    public function setMyKey($myKeyValue)
1768
    {
1769
        $res = parent::setMyKey($myKeyValue);
1770
        $this->updateApiURL();
1771
        return $res;
1772
    }
1773
1774
    /**
1775
     * Set or get ignore not found pages flag
1776
     *
1777
     * @param boolean $ignore set flag to
1778
     *
1779
     * @return boolean get flag state
1780
     */
1781
    public function ignore404($ignore = null)
1782
    {
1783
        if (!is_null($ignore)) {
1784
            $this->ignoreNotFound = $ignore;
1785
        }
1786
        return $this->ignoreNotFound;
1787
    }
1788
1789
    /**
1790
     * Send Document by mail
1791
     *
1792
     * @url https://www.flexibee.eu/api/dokumentace/ref/odesilani-mailem/
1793
     *
1794
     * @param string $to
1795
     * @param string $subject
1796
     * @param string $body Email Text
1797
     *
1798
     * @return int http response code
1799
     */
1800
    public function sendByMail($to, $subject, $body, $cc = null)
1801
    {
1802
        $this->setPostFields($body);
1803
        $result = $this->doCurlRequest(urlencode($this->getRecordID()).'/odeslani-dokladu?to='.$to.'&subject='.urlencode($subject).'&cc='.$cc
1804
            , 'PUT', 'xml');
1805
        return $result == 200;
1806
    }
1807
1808
    /**
1809
     * Send all unsent Invoices by mail
1810
     *
1811
     * @url https://www.flexibee.eu/api/dokumentace/ref/odesilani-mailem/
1812
     * @return int http response code
1813
     */
1814
    public function sendUnsent()
1815
    {
1816
        return $this->doCurlRequest('automaticky-odeslat-neodeslane', 'PUT',
1817
                'xml');
1818
    }
1819
1820
    /**
1821
     * FlexiBee date to PHP DateTime
1822
     *
1823
     * @param string $flexidate
1824
     *
1825
     * @return \DateTime | false
1826
     */
1827
    public static function flexiDateToDateTime($flexidate)
1828
    {
1829
        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 1829 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...
1830
    }
1831
1832
    /**
1833
     * Získá dokument v daném formátu
1834
     * Obtain document in given format
1835
     *
1836
     * @param string $format  pdf/csv/xml/json/ ...
1837
     *
1838
     * @return string|null filename downloaded or none
1839
     */
1840
    public function getInFormat($format)
1841
    {
1842
        $response = null;
1843
        if ($this->setFormat($format)) {
1844
            if (($this->doCurlRequest(($format == 'html') ? $this->apiURL.'?inDesktopApp=true'
1845
                            : $this->apiURL, 'GET') == 200)) {
1846
                $response = $this->lastCurlResponse;
1847
            }
1848
        }
1849
        return $response;
1850
    }
1851
1852
    /**
1853
     * Uloží dokument v daném formátu do složky v systému souborů
1854
     * Save document in given format to directory in filesystem
1855
     *
1856
     * @param string $format  pdf/csv/xml/json/ ...
1857
     * @param string $destDir where to put file (prefix)
1858
     *
1859
     * @return string|null filename downloaded or none
1860
     */
1861
    public function downloadInFormat($format, $destDir = './')
1862
    {
1863
        $fileOnDisk = null;
1864
        if ($this->setFormat($format)) {
1865
            $downloadTo = $destDir.$this->getEvidence().'_'.$this->getMyKey().'.'.$format;
1866
            if (($this->doCurlRequest($this->apiURL, 'GET') == 200) && (file_put_contents($downloadTo,
1867
                    $this->lastCurlResponse) !== false)) {
1868
                $fileOnDisk = $downloadTo;
1869
            }
1870
        }
1871
        return $fileOnDisk;
1872
    }
1873
1874
    /**
1875
     * Compile and send Report about Error500 to FlexiBee developers
1876
     * If FlexiBee is running on localost try also include java backtrace
1877
     *
1878
     * @param array $errorResponse result of parseError();
1879
     */
1880
    public function error500Reporter($errorResponse)
1881
    {
1882
        $ur = str_replace('/c/'.$this->company, '',
1883
            str_replace($this->url, '', $this->curlInfo['url']));
1884
        if (!array_key_exists($ur, $this->reports)) {
1885
            $tmpdir   = sys_get_temp_dir();
1886
            $myTime   = $this->curlInfo['when'];
1887
            $curlname = $tmpdir.'/curl-'.$this->evidence.'-'.$myTime.'.json';
1888
            file_put_contents($curlname,
1889
                json_encode($this->curlInfo, JSON_PRETTY_PRINT));
1890
1891
            $report = new \Ease\Mailer($this->reportRecipient,
1892
                'Error report 500 - '.$ur);
1893
1894
            $d     = dir($tmpdir);
1895
            while (false !== ($entry = $d->read())) {
1896
                if (strstr($entry, $myTime)) {
1897
                    $ext  = pathinfo($tmpdir.'/'.$entry, PATHINFO_EXTENSION);
1898
                    $mime = Formats::suffixToContentType($ext);
1899
                    $report->addFile($tmpdir.'/'.$entry,
1900
                        empty($mime) ? 'text/plain' : $mime);
1901
                }
1902
            }
1903
            $d->close();
1904
1905
            if ((strstr($this->url, '://localhost') || strstr($this->url,
1906
                    '://127.')) && file_exists('/var/log/flexibee.log')) {
1907
1908
                $fl = fopen("/var/log/flexibee.log", "r");
1909
                if ($fl) {
1910
                    $tracelog = [];
1911
                    for ($x_pos = 0, $ln = 0, $output = array(); fseek($fl,
1912
                            $x_pos, SEEK_END) !== -1; $x_pos--) {
1913
                        $char = fgetc($fl);
1914
                        if ($char === "\n") {
1915
                            $tracelog[] = $output[$ln];
1916
                            if (strstr($output[$ln], $errorResponse['message'])) {
1917
                                break;
1918
                            }
1919
                            $ln++;
1920
                            continue;
1921
                        }
1922
                        $output[$ln] = $char.((array_key_exists($ln, $output)) ? $output[$ln]
1923
                                : '');
1924
                    }
1925
1926
                    $trace     = implode("\n", array_reverse($tracelog));
1927
                    $tracefile = $tmpdir.'/trace-'.$this->evidence.'-'.$myTime.'.log';
1928
                    file_put_contents($tracefile, $trace);
1929
                    $report->addItem("\n\n".$trace);
1930
                    fclose($fl);
1931
                }
1932
            } else {
1933
                $report->addItem($errorResponse['message']);
1934
            }
1935
1936
            $licenseInfo = $this->performRequest($this->url.'/default-license.json');
1937
1938
            $report->addItem("\n\n".json_encode($licenseInfo['license'],
1939
                    JSON_PRETTY_PRINT));
1940
1941
            if ($report->send()) {
1942
                $this->reports[$ur] = $myTime;
1943
            }
1944
        }
1945
    }
1946
1947
    /**
1948
     * Returns code:CODE
1949
     *
1950
     * @param string $code
1951
     *
1952
     * @return string
1953
     */
1954 10
    public static function code($code)
1955
    {
1956 10
        return 'code:'.self::uncode($code);
1957
    }
1958
1959
    /**
1960
     * Returns CODE without code: prefix
1961
     *
1962
     * @param string $code
1963
     *
1964
     * @return string
1965
     */
1966 10
    public static function uncode($code)
1967
    {
1968 10
        return str_replace(['code:', 'code%3A'], '', $code);
1969
    }
1970
1971
    /**
1972
     * Reconnect After unserialization
1973
     */
1974
    public function __wakeup()
1975
    {
1976
        parent::__wakeup();
1977
        $this->curlInit();
1978
    }
1979
}
1980