Test Failed
Push — master ( cc2d13...fdb64f )
by Vítězslav
07:05
created

FlexiBeeRO::setEvidence()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 25
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 4.1106

Importance

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

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2050
    {
2051 23
        $this->addStatusMessage('FlexiBee '.str_replace('://',
2052 23
                '://'.$this->user.'@', str_replace('.json', '', $this->apiURL)).' FlexiPeeHP v'.self::$libVersion.' (FlexiBee '.EvidenceList::$version.') EasePHP Framework v'.\Ease\Atom::$frameworkVersion.' '.$additions,
2053 23
            'debug');
2054 23
    }
2055
2056
    /**
2057
     * Reconnect After unserialization
2058
     */
2059
    public function __wakeup()
2060
    {
2061
        parent::__wakeup();
2062
        $this->curlInit();
2063
    }
2064
}