Passed
Push — master ( 74c932...1b6587 )
by Vítězslav
02:09
created

FlexiBeeRO::urlizeId()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.0218

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 10
c 0
b 0
f 0
ccs 8
cts 9
cp 0.8889
rs 10
cc 4
nc 4
nop 1
crap 4.0218
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-2018 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\Sand
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.20';
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
        'add-global-version',
271
        'add-row-count',
272
        'as-gui',
273
        'auth',
274
        'authSessionId',
275
        'code-as-id',
276
        'code-in-response',
277
        'delimeter',
278
        'detail', //See: https://www.flexibee.eu/api/dokumentace/ref/detail-levels
279
        'dir',
280
        'dry-run', // See: https://www.flexibee.eu/api/dokumentace/ref/dry-run/
281
        'encoding',
282
        'export-settings',
283
        'fail-on-warning',
284
        'filter',
285
        'format',
286
        'idUcetniObdobi',
287
        'includes',
288
        'inDesktopApp', // Note: Undocumented function (html only)
289
        'limit',
290
        'mode',
291
        'no-ext-ids',
292
        'no-http-errors',
293
        'no-ids',
294
        'only-ext-ids',
295
        'order',
296
        'relations',
297
        'report-lang',
298
        'report-name',
299
        'report-sign',
300
        'skupina-stitku',
301
        'sort',
302
        'start',
303
        'stitky-as-ids',
304
        'use-ext-id',
305
        'use-internal-id',
306
        'xpath', // See: https://www.flexibee.eu/api/dokumentace/ref/xpath/
307
    ];
308
309
    /**
310
     * Session ID
311
     * @var string
312
     */
313
    public $authSessionId = null;
314
315
    /**
316
     * Token obtained during login procedure
317
     * @var string 
318
     */
319
    public $refreshToken = null;
320
321
    /**
322
     * Save 404 results to log ?
323
     * @var boolean
324
     */
325
    protected $ignoreNotFound = false;
326
327
    /**
328
     * Array of errors caused by last request
329
     * @var array
330
     */
331
    private $errors = [];
332
333
    /**
334
     * List of Error500 reports sent
335
     * @var array
336
     */
337
    private $reports = [];
338
339
    /**
340 70
     * Send Error500 Report to
341
     * @var string email address
342 70
     */
343
    public $reportRecipient = '[email protected]';
344 70
345 70
    /**
346 70
     * Formating string for \DateTime::format() for datetime columns
347 70
     * @var string
348 22
     */
349 22
    static public $DateTimeFormat = 'Y-m-d\TH:i:s.u+P';
350 70
351
    /**
352
     * Formating string for \DateTime::format() for date columns
353
     * @var string
354
     */
355
    static public $DateFormat = 'Y-m-d';
356
357
    /**
358 71
     * Last Request response stats
359
     * @var array 
360 71
     */
361 71
    private $responseStats = null;
362 71
363 71
    /**
364 71
     * Chained Objects
365 23
     * @var array
366 23
     */
367 71
    public $chained = [];
368 71
369 23
    /**
370 23
     * We Connect to server by default
371 71
     * @var boolean
372
     */
373
    public $offline = false;
374 71
375 71
    /**
376 71
     * Override cURL timeout
377
     * @var int seconds
378
     */
379
    public $timeout = null;
380
381
    /**
382
     * Columns Info for serveral evidencies
383
     * @var array 
384
     */
385 48
    private $columnsInfo = [];
386
387 48
    /**
388
     * Class for read only interaction with FlexiBee.
389
     *
390 48
     * @param mixed $init default record id or initial data
391 48
     * @param array $options Connection settings and other options override
392 48
     */
393
    public function __construct($init = null, $options = [])
394 48
    {
395
        $this->init = $init;
396
397
        parent::__construct();
398
        $this->setUp($options);
399 94
        $this->curlInit();
400
        if (!empty($init)) {
401 94
            $this->processInit($init);
402 94
        }
403 94
    }
404 94
405 94
    /**
406 94
     * Set internal Object name
407 94
     *
408 94
     * @param string $objectName
409 94
     *
410 94
     * @return string Jméno objektu
411
     */
412
    public function setObjectName($objectName = null)
413
    {
414
        return parent::setObjectName(is_null($objectName) ? ( empty($this->getRecordIdent())
415
                    ? $this->getObjectName() : $this->getRecordIdent().'@'.$this->getObjectName() )
416
                    : $objectName);
417
    }
418
419
    /**
420
     * SetUp Object to be ready for work
421
     *
422
     * @param array $options Object Options ( user,password,authSessionId
423 13
     *                                        company,url,evidence,
424
     *                                        prefix,defaultUrlParams,debug,
425 13
     *                                        detail,offline,filter,ignore404
426 10
     *                                        timeout
427 13
     */
428 13
    public function setUp($options = [])
429 13
    {
430 10
        $this->setupProperty($options, 'company', 'FLEXIBEE_COMPANY');
431 10
        $this->setupProperty($options, 'url', 'FLEXIBEE_URL');
432 10
        $this->setupProperty($options, 'user', 'FLEXIBEE_LOGIN');
433 8
        $this->setupProperty($options, 'password', 'FLEXIBEE_PASSWORD');
434
        $this->setupProperty($options, 'authSessionId', 'FLEXIBEE_AUTHSESSID');
435 13
        $this->setupProperty($options, 'timeout', 'FLEXIBEE_TIMEOUT');
436
        if (!empty($this->authSessionId)) {
437
            $this->defaultHttpHeaders['X-authSessionId'] = $this->authSessionId;
438
        }
439
        if (isset($options['evidence'])) {
440
            $this->setEvidence($options['evidence']);
441
        }
442 23
        $this->setupProperty($options, 'defaultUrlParams');
443
        if (isset($options['prefix'])) {
444
            $this->setPrefix($options['prefix']);
445 23
        }
446 23
        if (array_key_exists('detail', $options)) {
447 23
            $this->defaultUrlParams['detail'] = $options['detail'];
448 23
        }
449 23
        $this->setupProperty($options, 'filter');
450 23
        if (array_key_exists('offline', $options)) {
451 23
            $this->offline = (boolean) $options['offline'];
452 23
        }
453 23
454 23
        if (array_key_exists('ignore404', $options)) {
455 23
            $this->ignore404($options['ignore404']);
456 23
        }
457 23
458 23
        $this->setupProperty($options, 'debug');
459 23
        $this->updateApiURL();
460 23
    }
461 23
462 23
    /**
463
     * Set up one of properties
464
     *
465
     * @param array  $options  array of given properties
466
     * @param string $name     name of property to process
467
     * @param string $constant load default property value from constant
468
     */
469
    public function setupProperty($options, $name, $constant = null)
470
    {
471 23
        if (array_key_exists($name, $options)) {
472
            $this->$name = $options[$name];
473 23
        } else {
474 23
            if (property_exists($this, $name) && !empty($constant) && defined($constant)) {
475
                $this->$name = constant($constant);
476
            }
477
        }
478
    }
479
480 23
    /**
481 23
     * Get Current connection options for use in another object
482 23
     *
483 23
     * @return array usable as second constructor parameter
484 23
     */
485
    public function getConnectionOptions()
486
    {
487
        $conOpts = ['url' => $this->url];
488
        if (empty($this->authSessionId)) {
489
            $conOpts ['user']    = $this->user;
490
            $conOpts['password'] = $this->password;
491
        } else {
492
            $conOpts['authSessionId'] = $this->authSessionId;
493
        }
494 23
        $company = $this->getCompany();
495
        if (!empty($company)) {
496 23
            $conOpts['company'] = $company;
497 23
        }
498 23
        if (!is_null($this->timeout)) {
0 ignored issues
show
introduced by
The condition is_null($this->timeout) is always false.
Loading history...
499 23
            $conOpts['timeout'] = $this->timeout;
500
        }
501
        return $conOpts;
502
    }
503 23
504 23
    /**
505
     * Inicializace CURL
506
     *
507 20
     * @return boolean Online Status
508 20
     */
509
    public function curlInit()
510 20
    {
511 3
        if ($this->offline === false) {
512 3
            $this->curl = \curl_init(); // create curl resource
513 3
            curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); // return content as a string from curl_exec
514 3
            curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true); // follow redirects (compatibility for future changes in FlexiBee)
515 23
            curl_setopt($this->curl, CURLOPT_HTTPAUTH, true);       // HTTP authentication
516 23
            curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false); // FlexiBee by default uses Self-Signed certificates
517 23
            curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false);
518
            curl_setopt($this->curl, CURLOPT_VERBOSE, ($this->debug === true)); // For debugging
519
            if (empty($this->authSessionId)) {
520
                curl_setopt($this->curl, CURLOPT_USERPWD,
521
                    $this->user.':'.$this->password); // set username and password
522
            }
523
            if (!is_null($this->timeout)) {
0 ignored issues
show
introduced by
The condition is_null($this->timeout) is always false.
Loading history...
524
                curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->timeout);
525
            }
526 69
        }
527
        return !$this->offline;
528 69
    }
529
530
    /**
531
     * Zinicializuje objekt dle daných dat. Možné hodnoty:
532
     *
533
     *  * 234                              - interní číslo záznamu k načtení
534
     *  * code:LOPATA                      - kód záznamu
535
     *  * BAGR                             - kód záznamu k načtení
536
     *  * ['id'=>24,'nazev'=>'hoblík']     - pole hodnot k předvyplnění
537 23
     *  * 743.json?relations=adresa,vazby  - část url s parametry k načtení
538
     *
539 23
     * @param mixed $init číslo/"(code:)kód"/(část)URI záznamu k načtení | pole hodnot k předvyplnění
540 23
     */
541
    public function processInit($init)
542
    {
543
        if (is_integer($init)) {
544
            $this->loadFromFlexiBee($init);
545
        } elseif (is_array($init)) {
546
            $this->takeData($init);
547
        } elseif (preg_match('/\.(json|xml|csv)/', $init)) {
548 23
            $this->takeData($this->getFlexiData((($init[0] != '/') ? $this->evidenceUrlWithSuffix($init)
549
                            : $init)));
550 23
        } else {
551
            $this->loadFromFlexiBee($init);
552
        }
553
    }
554
555
    /**
556
     * Set Data Field value
557
     *
558 25
     * @param string $columnName field name
559
     * @param mixed  $value      field data value
560 25
     *
561 25
     * @return bool Success
562
     */
563
    public function setDataValue($columnName, $value)
564 25
    {
565 1
        switch ($columnName) {
566 1
            case 'kod':
567 24
                $value = self::uncode($value); //Alwyas uncode "kod" column
568 24
                break;
569 24
            default:
570 25
                break;
571 25
        }
572
        if (is_object($value)) {
573
            switch (get_class($value)) {
574
                case 'DateTime':
575
                    $columnInfo = $this->getColumnInfo($columnName);
576
                    switch ($columnInfo['type']) {
577
                        case 'date':
578
                            $value = self::dateToFlexiDate($value);
579
                            break;
580
                        case 'datetime':
581 23
                            $value = self::dateToFlexiDateTime($value);
582
                            break;
583 23
                    }
584 23
                    break;
585 23
            }
586 23
        }
587 23
        return parent::setDataValue($columnName, $value);
588 23
    }
589 23
590 23
    /**
591 23
     * PHP Date object to FlexiBee date format
592 23
     * 
593 23
     * @param \DateTime $date
594 23
     */
595 23
    public static function dateToFlexiDate($date)
596
    {
597
        return $date->format(self::$DateFormat);
598
    }
599 23
600
    /**
601
     * PHP Date object to FlexiBee date format
602
     * 
603
     * @param \DateTime $dateTime
604
     */
605
    public static function dateToFlexiDateTime($dateTime)
606
    {
607
        return $dateTime->format(self::$DateTimeFormat);
608
    }
609 23
610
    /**
611 23
     * Set URL prefix
612 23
     *
613 22
     * @param string $prefix
614 22
     */
615 23
    public function setPrefix($prefix)
616 17
    {
617 17
        switch ($prefix) {
618 17
            case 'a': //Access
619 17
            case 'c': //Company
620 23
            case 'u': //User
621
            case 'g': //License Groups
622
            case 'admin':
623
            case 'status':
624 23
            case 'login-logout':
625
                $this->prefix = '/'.$prefix.'/';
626
                break;
627
            case null:
628
            case '':
629
            case '/':
630
                $this->prefix = '';
631
                break;
632
            default:
633
                throw new \Exception(sprintf('Unknown prefix %s', $prefix));
634 68
        }
635
    }
636 68
637 68
    /**
638 68
     * Set communication format.
639 62
     * One of html|xml|json|csv|dbf|xls|isdoc|isdocx|edi|pdf|pdf|vcf|ical
640 62
     *
641 68
     * @param string $format
642
     * 
643
     * @return boolen format is availble
0 ignored issues
show
Bug introduced by
The type FlexiPeeHP\boolen was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
644
     */
645
    public function setFormat($format)
646
    {
647
        $result = true;
648
        if (($this->debug === true) && !empty($this->evidence) && isset(Formats::$$this->evidence)) {
649
            if (array_key_exists($format, array_flip(Formats::$$this->evidence))
650
                === false) {
651 23
                $result = false;
652
            }
653 23
        }
654 23
        if ($result === true) {
655 23
            $this->format = $format;
656 23
            $this->updateApiURL();
657 23
        }
658 23
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result returns the type boolean which is incompatible with the documented return type FlexiPeeHP\boolen.
Loading history...
659 23
    }
660 23
661 23
    /**
662
     * Nastaví Evidenci pro Komunikaci.
663
     * Set evidence for communication
664
     *
665
     * @param string $evidence evidence pathName to use
666
     * 
667 48
     * @return boolean evidence switching status
668
     */
669 48
    public function setEvidence($evidence)
670 48
    {
671 48
        switch ($this->prefix) {
672
            case '/c/':
673
                if ($this->debug === true) {
674 48
                    if (array_key_exists($evidence, EvidenceList::$name)) {
675 48
                        $this->evidence = $evidence;
676
                        $result         = true;
677
                    } else {
678
                        throw new \Exception(sprintf('Try to set unsupported evidence %s',
679
                            $evidence));
680
                    }
681
                } else {
682
                    $this->evidence = $evidence;
683
                    $result         = true;
684
                }
685
                break;
686 23
            default:
687
                $this->evidence = $evidence;
688 23
                $result         = true;
689 23
                break;
690 23
        }
691 23
        $this->updateApiURL();
692 23
        return $result;
693 23
    }
694 23
695 23
    /**
696 23
     * Vrací právě používanou evidenci pro komunikaci
697 23
     * Obtain current used evidence
698 23
     *
699 23
     * @return string
700 23
     */
701
    public function getEvidence()
702
    {
703 23
        return $this->evidence;
704 23
    }
705 23
706
    /**
707
     * Set used company.
708 23
     * Nastaví Firmu.
709
     *
710
     * @param string $company
711
     */
712
    public function setCompany($company)
713
    {
714
        $this->company = $company;
715
    }
716
717
    /**
718 23
     * Obtain company now used
719
     * Vrací právě používanou firmu
720 23
     *
721
     * @return string
722
     */
723
    public function getCompany()
724
    {
725
        return $this->company;
726
    }
727
728
    /**
729
     * Vrací název evidence použité v odpovědích z FlexiBee
730
     *
731 25
     * @return string
732
     */
733
    public function getResponseEvidence()
734 25
    {
735
        switch ($this->evidence) {
736 25
            case 'c':
737
                $evidence = 'company';
738 25
                break;
739 4
            case 'evidence-list':
740 4
                $evidence = 'evidence';
741 22
                break;
742
            default:
743
                $evidence = $this->getEvidence();
744 25
                break;
745
        }
746 25
        return $evidence;
747 25
    }
748
749
    /**
750
     * Převede rekurzivně Objekt na pole.
751
     *
752
     * @param object|array $object
753
     *
754
     * @return array
755
     */
756
    public static function object2array($object)
757
    {
758 3
        $result = null;
759
        if (is_object($object)) {
760 3
            $objectData = get_object_vars($object);
761
            if (is_array($objectData) && count($objectData)) {
762 3
                $result = array_map('self::object2array', $objectData);
763 3
            }
764 3
        } else {
765
            if (is_array($object)) {
0 ignored issues
show
introduced by
The condition is_array($object) is always true.
Loading history...
766
                foreach ($object as $item => $value) {
767
                    $result[$item] = self::object2array($value);
768
                }
769
            } else {
770
                $result = $object;
771
            }
772
        }
773 3
774
        return $result;
775 3
    }
776
777
    /**
778
     * Převede rekurzivně v poli všechny objekty na jejich identifikátory.
779
     *
780
     * @param object|array $object
781
     *
782
     * @return array
783
     */
784
    public static function objectToID($object)
785 3
    {
786
        $resultID = null;
787 3
        if (is_object($object) && method_exists($object, '__toString')
788 3
        ) {
789 3
            $resultID = $object->__toString();
790 3
        } else {
791
            if (is_array($object)) {
792
                foreach ($object as $item => $value) {
793 3
                    $resultID[$item] = self::objectToID($value);
794
                }
795
            } else { //String
796
                $resultID = $object;
797 3
            }
798
        }
799
800
        return $resultID;
801
    }
802
803
    /**
804
     * Return basic URL for used Evidence
805
     *
806
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Sestavování URL
807
     *
808
     * @return string Evidence URL
809
     */
810
    public function getEvidenceURL()
811
    {
812
        $evidenceUrl = $this->url.$this->prefix.$this->company;
813
        $evidence    = $this->getEvidence();
814
        if (!empty($evidence)) {
815
            $evidenceUrl .= '/'.$evidence;
816
        }
817
        return $evidenceUrl;
818
    }
819
820 3
    /**
821
     * Add suffix to Evidence URL
822 3
     *
823
     * @param string $urlSuffix
824 3
     *
825
     * @return string
826
     */
827
    public function evidenceUrlWithSuffix($urlSuffix)
828
    {
829
        $evidenceUrl = $this->getEvidenceUrl();
830
        if (!empty($urlSuffix)) {
831
            if (($urlSuffix[0] != '/') && ($urlSuffix[0] != ';') && ($urlSuffix[0]
832 3
                != '?')) {
833 3
                $evidenceUrl .= '/';
834 3
            }
835
            $evidenceUrl .= $urlSuffix;
836
        }
837 3
        return $evidenceUrl;
838
    }
839
840 3
    /**
841
     * Update $this->apiURL
842
     */
843
    public function updateApiURL()
844
    {
845
        $this->apiURL = $this->getEvidenceURL();
846
        $id           = $this->getRecordID();
847
        if (empty($id)) {
848
            $id = $this->getRecordCode();
849
        }
850
        if (!empty($id)) {
851
            $this->apiURL .= '/'.self::urlEncode($id);
852
        }
853
        $this->apiURL .= '.'.$this->format;
854
    }
855
    /*
856
     * Add Default Url params to given url if not overrided
857
     *
858
     * @param string $urlRaw
859
     *
860 3
     * @return string url with default params added
861
     */
862
863
    public function addDefaultUrlParams($urlRaw)
864
    {
865
        return \Ease\Shared::addUrlParams($urlRaw, $this->defaultUrlParams,
866
                false);
867
    }
868
869
    /**
870
     * Funkce, která provede I/O operaci a vyhodnotí výsledek.
871
     *
872
     * @param string $urlSuffix část URL za identifikátorem firmy.
873
     * @param string $method    HTTP/REST metoda
874
     * @param string $format    Requested format
875
     * 
876
     * @return array|boolean Výsledek operace
877
     */
878
    public function performRequest($urlSuffix = null, $method = 'GET',
879
                                   $format = null)
880
    {
881
        $this->rowCount      = null;
882
        $this->responseStats = [];
883
884
        if (preg_match('/^http/', $urlSuffix)) {
885
            $url = $urlSuffix;
886
        } elseif (strlen($urlSuffix) && ($urlSuffix[0] == '/')) {
887
            $url = $this->url.$urlSuffix;
888
        } else {
889
            $url = $this->evidenceUrlWithSuffix($urlSuffix);
890 3
        }
891
892 3
        $responseCode = $this->doCurlRequest($this->addDefaultUrlParams($url),
893 3
            $method, $format);
894 3
895 3
        return $this->parseResponse($this->rawResponseToArray($this->lastCurlResponse,
896
                    $this->responseFormat), $responseCode);
897 3
    }
898
899 3
    /**
900
     * Parse Raw FlexiBee response in several formats
901 3
     *
902
     * @param string $responseRaw raw response body
903 3
     * @param string $format      Raw Response format json|xml|etc
904
     *
905 3
     * @return array
906 3
     */
907 3
    public function rawResponseToArray($responseRaw, $format)
908 3
    {
909 3
        $responseDecoded = [];
910 3
        if (!empty(trim($responseRaw))) {
911 3
            switch ($format) {
912 3
                case 'json':
913 3
                    $responseDecoded = $this->rawJsonToArray($responseRaw);
914 3
                    break;
915 3
                case 'xml':
916 3
                    $responseDecoded = $this->rawXmlToArray($this->lastCurlResponse);
917 3
                    break;
918
                case 'txt':
919 3
                default:
920
                    $responseDecoded = [$this->lastCurlResponse];
921
                    break;
922 3
            }
923 3
        }
924 3
        return $responseDecoded;
925 3
    }
926 3
927 3
    /**
928 3
     * Convert FlexiBee Response JSON to Array
929 3
     *
930 3
     * @param string $rawJson
931
     *
932
     * @return array
933
     */
934
    public function rawJsonToArray($rawJson)
935 3
    {
936
        $responseDecoded = json_decode($rawJson, true, 10);
937
        $decodeError     = json_last_error_msg();
938
        if ($decodeError == 'No error') {
939 3
            if (array_key_exists($this->nameSpace, $responseDecoded)) {
940
                $responseDecoded = $responseDecoded[$this->nameSpace];
941
            }
942
        } else {
943
            $this->addStatusMessage('JSON Decoder: '.$decodeError, 'error');
944
            $this->addStatusMessage($rawJson, 'debug');
945
        }
946
        return $responseDecoded;
947
    }
948
949 23
    /**
950
     * Convert FlexiBee Response XML to Array
951 23
     *
952 23
     * @param string $rawXML
953 23
     *
954 23
     * @return array
955 15
     */
956 15
    public function rawXmlToArray($rawXML)
957 15
    {
958 23
        return self::xml2array($rawXML);
959
    }
960
961
    /**
962
     * Parse Response array
963
     *
964
     * @param array $responseDecoded
965
     * @param int $responseCode Request Response Code
966
     *
967
     * @return array main data part of response
968 23
     */
969
    public function parseResponse($responseDecoded, $responseCode)
970 23
    {
971 23
        if (is_array($responseDecoded)) {
0 ignored issues
show
introduced by
The condition is_array($responseDecoded) is always true.
Loading history...
972 23
            $mainResult          = $this->unifyResponseFormat($responseDecoded);
973 23
            $this->responseStats = array_key_exists('stats', $responseDecoded) ? (isset($responseDecoded['stats'][0])
974 23
                    ? $responseDecoded['stats'][0] : $responseDecoded['stats']) : null;
975
        } else {
976 23
            $mainResult = $responseDecoded;
977 23
        }
978 23
        switch ($responseCode) {
979 23
            case 201: //Success Write
980 23
            case 200: //Success Read
981
                if (is_array($responseDecoded)) {
0 ignored issues
show
introduced by
The condition is_array($responseDecoded) is always true.
Loading history...
982 23
                    $this->lastResult = $mainResult;
983 23
                    if (isset($responseDecoded['@rowCount'])) {
984 23
                        $this->rowCount = (int) $responseDecoded['@rowCount'];
985
                    }
986
                    if (isset($responseDecoded['@globalVersion'])) {
987
                        $this->globalVersion = (int) $responseDecoded['@globalVersion'];
988
                    }
989
                }
990 1
                break;
991
992 1
            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...
993 1
                if ($this->debug === true) {
994 1
                    $this->error500Reporter($responseDecoded);
995 1
                }
996 1
            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...
997
                if ($this->ignoreNotFound === true) {
998
                    break;
999
                }
1000
            case 400: //Bad Request parameters
1001 1
            default: //Something goes wrong
1002
                $this->addStatusMessage($this->lastResponseCode.': '.$this->curlInfo['url'],
1003 1
                    'warning');
1004 1
                if (is_array($responseDecoded)) {
0 ignored issues
show
introduced by
The condition is_array($responseDecoded) is always true.
Loading history...
1005
                    $this->parseError($responseDecoded);
1006
                }
1007
                $this->logResult($responseDecoded, $this->curlInfo['url']);
1008
                break;
1009
        }
1010
        return $mainResult;
1011
    }
1012
1013 23
    /**
1014
     * Parse error message response
1015 23
     *
1016 23
     * @param array $responseDecoded
1017 22
     * 
1018
     * @return int number of errors processed
1019
     */
1020
    public function parseError(array $responseDecoded)
1021 22
    {
1022
        if (array_key_exists('results', $responseDecoded)) {
1023
            $this->errors = $responseDecoded['results'][0]['errors'];
1024
            foreach ($this->errors as $errorInfo) {
1025
                $this->addStatusMessage($errorInfo['message'], 'error');
1026
                if (array_key_exists('for', $errorInfo)) {
1027
                    unset($errorInfo['message']);
1028
                    $this->addStatusMessage(json_encode($errorInfo), 'debug');
1029
                }
1030
            }
1031
        } else {
1032
            if (array_key_exists('message', $responseDecoded)) {
1033
                $this->errors = [['message' => $responseDecoded['message']]];
1034
            }
1035
        }
1036
        return count($this->errors);
1037
    }
1038
1039
    /**
1040
     * Vykonej HTTP požadavek
1041
     *
1042
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Sestavování URL
1043
     * @param string $url    URL požadavku
1044
     * @param string $method HTTP Method GET|POST|PUT|OPTIONS|DELETE
1045
     * @param string $format požadovaný formát komunikace
1046
     * 
1047
     * @return int HTTP Response CODE
1048
     */
1049
    public function doCurlRequest($url, $method, $format = null)
1050
    {
1051
        if (is_null($format)) {
1052
            $format = $this->format;
1053
        }
1054
        curl_setopt($this->curl, CURLOPT_URL, $url);
1055
// Nastavení samotné operace
1056
        curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, strtoupper($method));
1057
//Vždy nastavíme byť i prázná postdata jako ochranu před chybou 411
1058
        curl_setopt($this->curl, CURLOPT_POSTFIELDS, $this->postFields);
1059 15
1060
        $httpHeaders = $this->defaultHttpHeaders;
1061 15
1062 15
        $formats = Formats::bySuffix();
1063
1064 15
        if (!isset($httpHeaders['Accept'])) {
1065 8
            $httpHeaders['Accept'] = $formats[$format]['content-type'];
1066 7
        }
1067 7
        if (!isset($httpHeaders['Content-Type'])) {
1068 7
            $httpHeaders['Content-Type'] = $formats[$format]['content-type'];
1069
        }
1070 8
        $httpHeadersFinal = [];
1071 1
        foreach ($httpHeaders as $key => $value) {
1072 1
            if (($key == 'User-Agent') && ($value == 'FlexiPeeHP')) {
1073 8
                $value .= ' v'.self::$libVersion;
1074
            }
1075 15
            $httpHeadersFinal[] = $key.': '.$value;
1076 4
        }
1077 4
1078 4
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, $httpHeadersFinal);
1079
1080
// Proveď samotnou operaci
1081
        $this->lastCurlResponse            = curl_exec($this->curl);
1082
        $this->curlInfo                    = curl_getinfo($this->curl);
1083 4
        $this->curlInfo['when']            = microtime();
1084
        $this->curlInfo['request_headers'] = $httpHeadersFinal;
1085 15
        $this->responseFormat              = $this->contentTypeToResponseFormat($this->curlInfo['content_type'],
1086
            $url);
1087 15
        $this->lastResponseCode            = $this->curlInfo['http_code'];
1088 15
        $this->lastCurlError               = curl_error($this->curl);
1089
        if (strlen($this->lastCurlError)) {
1090
            $this->addStatusMessage(sprintf('Curl Error (HTTP %d): %s',
1091 15
                    $this->lastResponseCode, $this->lastCurlError), 'error');
1092
        }
1093 15
1094 15
        if ($this->debug === true) {
1095 15
            $this->saveDebugFiles();
1096
        }
1097 15
1098
        return $this->lastResponseCode;
1099 15
    }
1100 15
1101 15
    /**
1102 9
     * Obtain json for application/json
1103 9
     * 
1104 6
     * @param string $contentType
1105 6
     * @param string $url
1106 9
     * 
1107 6
     * @return string response format
1108
     */
1109
    public function contentTypeToResponseFormat($contentType, $url = null)
1110 15
    {
1111
        if (!empty($url)) {
1112
            $url = parse_url($url, PHP_URL_PATH);
1113
        }
1114
1115
        $contentTypeClean = strstr($contentType, ';') ? substr($contentType, 0,
1116
                strpos($contentType, ';')) : $contentType;
1117
1118
        switch ($url) {
1119
            case '/login-logout/login';
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1120
                $responseFormat = 'json';
1121 23
                break;
1122
            default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1123 23
                switch ($contentTypeClean) {
1124 23
                    case 'text/javascript':
1125 23
                        $responseFormat = 'js';
1126 23
                        break;
1127 23
1128
                    default:
1129
                        $responseFormat = Formats::contentTypeToSuffix($contentTypeClean);
1130
                        break;
1131 23
                }
1132
                break;
1133
        }
1134
1135 23
        return $responseFormat;
1136 22
    }
1137 22
1138 9
    /**
1139 9
     * Nastaví druh prováděné akce.
1140 22
     *
1141
     * @link https://demo.flexibee.eu/devdoc/actions Provádění akcí
1142
     * @param string $action
1143
     * 
1144
     * @return boolean
1145
     */
1146
    public function setAction($action)
1147
    {
1148
        $result           = false;
1149
        $actionsAvailable = $this->getActionsInfo();
1150
        if (is_array($actionsAvailable) && array_key_exists($action,
1151 6
                $actionsAvailable)) {
1152
            $this->action = $action;
1153
            $result       = true;
1154 6
        }
1155 6
        return $result;
1156 6
    }
1157 6
1158 6
    /**
1159
     * Convert XML to array.
1160 6
     *
1161
     * @param string $xml
1162
     *
1163
     * @return array
1164
     */
1165 6
    public static function xml2array($xml)
1166
    {
1167
        $arr = [];
1168
        if (!empty($xml)) {
1169 6
            if (is_string($xml)) {
0 ignored issues
show
introduced by
The condition is_string($xml) is always true.
Loading history...
1170
                $xml = simplexml_load_string($xml);
1171
            }
1172
            foreach ($xml->attributes() as $a) {
1173
                $arr['@'.$a->getName()] = strval($a);
1174
            }
1175
            foreach ($xml->children() as $r) {
1176
                if (count($r->children()) == 0) {
1177 16
                    $arr[$r->getName()] = strval($r);
1178
                } else {
1179 16
                    $arr[$r->getName()][] = self::xml2array($r);
1180 9
                }
1181 9
            }
1182 16
        }
1183 16
        return $arr;
1184 16
    }
1185
1186 16
    /**
1187 16
     * Odpojení od FlexiBee.
1188 16
     */
1189 15
    public function disconnect()
1190 15
    {
1191
        if (is_resource($this->curl)) {
1192
            curl_close($this->curl);
1193
        }
1194
        $this->curl = null;
1195
    }
1196
1197
    /**
1198
     * Disconnect CURL befere pass away
1199 15
     */
1200
    public function __destruct()
1201
    {
1202 15
        $this->disconnect();
1203 10
    }
1204 10
1205 15
    /**
1206 15
     * Načte řádek dat z FlexiBee.
1207 15
     *
1208 15
     * @param int $recordID id požadovaného záznamu
1209
     *
1210 14
     * @return array
1211 14
     */
1212 14
    public function getFlexiRow($recordID)
1213 14
    {
1214 10
        $record   = null;
1215
        $response = $this->performRequest($this->evidence.'/'.$recordID.'.json');
1216 14
        if (isset($response[$this->evidence])) {
1217 14
            $record = $response[$this->evidence][0];
1218
        }
1219
1220
        return $record;
1221
    }
1222
1223
    /**
1224
     * Oddělí z pole podmínek ty jenž patří za ? v URL požadavku
1225
     *
1226
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls/ Sestavování URL
1227
     * @param array $conditions pole podmínek   - rendrují se do ()
1228
     * @param array $urlParams  pole parametrů  - rendrují za ?
1229
     */
1230
    public function extractUrlParams(&$conditions, &$urlParams)
1231
    {
1232
        foreach ($this->urlParams as $urlParam) {
1233
            if (isset($conditions[$urlParam])) {
1234
                \Ease\Sand::divDataArray($conditions, $urlParams, $urlParam);
1235
            }
1236
        }
1237
    }
1238
1239
    /**
1240
     * convert unicode to entities for use with FlexiBee queries
1241
     *
1242
     * @param string $urlRaw
1243
     * 
1244
     * @return string
1245
     */
1246
    public static function urlEncode($urlRaw)
1247
    {
1248
        return str_replace(['%27', '%3A'], ["'", ':'], rawurlencode($urlRaw));
1249
    }
1250
1251
    /**
1252 15
     * Načte data z FlexiBee.
1253
     *
1254
     * @param string $suffix     dotaz
1255 15
     * @param string|array $conditions Volitelný filtrovací výraz
1256 15
     *
1257 15
     * @return array Data obtained
1258
     */
1259 15
    public function getFlexiData($suffix = null, $conditions = null)
1260 15
    {
1261 15
        $finalUrl  = '';
1262 15
        $urlParams = $this->defaultUrlParams;
1263 15
1264 15
        if (!empty($conditions)) {
1265 15
            if (is_array($conditions)) {
1266 15
                $this->extractUrlParams($conditions, $urlParams);
1267
                $conditions = $this->flexiUrl($conditions);
1268 15
            }
1269
1270
            if (strlen($conditions) && ($conditions[0] != '/')) {
1271 15
                $conditions = '('.self::urlEncode($conditions).')';
1272
            }
1273
        }
1274 15
1275 15
        if (strlen($suffix)) {
1276 15
            if (preg_match('/^http/', $suffix) || ($suffix[0] == '/') || is_numeric($suffix)) {
1277 15
                $finalUrl = $suffix;
1278 15
            } else {
1279
                if (preg_match('/^(code|ext):(.*)/', $suffix, $matches)) {
1280 15
                    $finalUrl = $matches[1].':'.rawurlencode($matches[2]);
1281
                }
1282 15
            }
1283
        }
1284 15
1285 9
        $finalUrl .= $conditions;
1286 9
1287
        if (count($urlParams)) {
1288 15
            if (strstr($finalUrl, '?')) {
1289
                $finalUrl .= '&';
1290
            } else {
1291
                $finalUrl .= '?';
1292
            }
1293
            $finalUrl .= http_build_query($urlParams, null, '&',
1294
                PHP_QUERY_RFC3986);
1295
        }
1296
1297
        $transactions = $this->performRequest($finalUrl, 'GET');
1298
1299 23
        $responseEvidence = $this->getResponseEvidence();
1300
        if (is_array($transactions) && array_key_exists($responseEvidence,
1301 23
                $transactions)) {
1302
            $result = $transactions[$responseEvidence];
1303 23
            if ((count($result) == 1) && (count(current($result)) == 0 )) {
1304 23
                $result = null; // Response is empty Array
1305 23
            }
1306
        } else {
1307 23
            $result = $transactions;
1308 23
        }
1309 23
1310
        return $result;
1311 23
    }
1312 23
1313 23
    /**
1314 23
     * Načte záznam z FlexiBee a uloží v sobě jeho data
1315 23
     * Read FlexiBee record and store it inside od object
1316 23
     *
1317 23
     * @param int $id ID or conditions
1318 23
     *
1319 23
     * @return int počet načtených položek
1320 23
     */
1321
    public function loadFromFlexiBee($id = null)
1322
    {
1323
        $data = [];
1324 23
        if (is_null($id)) {
1325 23
            $id = $this->getMyKey();
1326 23
        }
1327
        $flexidata = $this->getFlexiData($this->getEvidenceUrl().'/'.self::urlizeId($id));
1328 23
        if ($this->lastResponseCode == 200) {
1329 23
            $this->apiURL = $this->curlInfo['url'];
1330 23
            if (is_array($flexidata) && (count($flexidata) == 1) && is_array(current($flexidata))) {
1331 23
                $data = current($flexidata);
1332
            }
1333
        }
1334 23
        return $this->takeData($data);
1335 23
    }
1336 23
1337 23
    /**
1338 23
     * Set Filter code for requests
1339 23
     *
1340 23
     * @link https://www.flexibee.eu/api/dokumentace/ref/zamykani-odemykani/
1341 23
     *
1342 23
     * @param array|string $filter filter formula or ['key'=>'value']
1343 23
     *
1344 23
     * @return string Filter code
1345 23
     */
1346
    public function setFilter($filter)
1347 23
    {
1348 23
        return $this->filter = is_array($filter) ? self::flexiUrl($filter) : $filter;
1349
    }
1350 23
1351
    /**
1352
     * Převede data do Json formátu pro FlexiBee.
1353
     * Convert data to FlexiBee like Json format
1354
     *
1355
     * @url https://www.flexibee.eu/api/dokumentace/ref/actions/
1356
     * @url https://www.flexibee.eu/api/dokumentace/ref/zamykani-odemykani/
1357
     *
1358
     * @param array $data    object data
1359
     * @param int   $options json_encode options like JSON_PRETTY_PRINT etc
1360 23
     *
1361
     * @return string
1362 23
     */
1363 23
    public function getJsonizedData($data = null, $options = 0)
1364 23
    {
1365
        if (is_null($data)) {
1366
            $data = $this->getData();
1367 23
        }
1368 23
1369 23
        $dataToJsonize = array_merge(['@version' => $this->protoVersion],
1370 23
            $this->getDataForJSON($data));
1371 23
        $jsonRaw       = json_encode([$this->nameSpace => $dataToJsonize],
1372
            $options);
1373
1374 23
        return $jsonRaw;
1375 23
    }
1376 23
1377
    /**
1378 23
     * Get Data Fragment specific for current object
1379 23
     *
1380 23
     * @param array $data
1381 23
     *
1382 23
     * @return array
1383
     */
1384 23
    public function getDataForJSON($data = null)
1385 23
    {
1386 23
        if (is_null($data)) {
1387 23
            $data = $this->getData();
1388 23
        }
1389
1390 23
        $dataForJson = [$this->getEvidence() => $this->objectToID($data)];
1391 23
1392 23
        if (!is_null($this->action)) {
0 ignored issues
show
introduced by
The condition is_null($this->action) is always false.
Loading history...
1393 23
            $dataForJson[$this->evidence.'@action'] = $this->action;
1394
            $this->action                           = null;
1395
        }
1396 23
1397
        if (!is_null($this->filter)) {
0 ignored issues
show
introduced by
The condition is_null($this->filter) is always false.
Loading history...
1398
            $dataForJson[$this->evidence.'@filter'] = $this->filter;
1399 23
        }
1400
1401
1402 23
        foreach ($this->chained as $chained) {
1403 23
            $chainedData = $chained->getDataForJSON();
1404 23
            foreach ($chainedData as $chainedItemEvidence => $chainedItemData) {
1405 23
                if (array_key_exists($chainedItemEvidence, $dataForJson)) {
1406 23
                    if (is_string(key($dataForJson[$chainedItemEvidence]))) {
1407 23
                        $dataBackup                          = $dataForJson[$chainedItemEvidence];
1408
                        $dataForJson[$chainedItemEvidence]   = [];
1409
                        $dataForJson[$chainedItemEvidence][] = $dataBackup;
1410
                    }
1411
                    if (array_key_exists(0, $chainedItemData)) {
1412
                        foreach ($chainedItemData as $chainedItem) {
1413
                            $dataForJson[$chainedItemEvidence][] = $chainedItem;
1414
                        }
1415
                    } else {
1416
                        $dataForJson[$chainedItemEvidence][] = $chainedItemData;
1417
                    }
1418
                } else {
1419
                    $dataForJson[$chainedItemEvidence] = $chainedItemData;
1420
                }
1421
            }
1422
        }
1423
1424
1425
        return $dataForJson;
1426
    }
1427
1428
    /**
1429
     * Join another FlexiPeeHP Object
1430
     *
1431
     * @param FlexiBeeRO $object
1432
     *
1433
     * @return boolean adding to stack success
1434
     */
1435
    public function join(&$object)
1436
    {
1437
        $result = true;
1438
        if (method_exists($object, 'getDataForJSON')) {
1439
            $this->chained[] = $object;
1440
        } else {
1441
            throw new \Ease\Exception('$object->getDataForJSON() does not exist');
1442
        }
1443
1444 23
        return $result;
1445
    }
1446 23
1447
    /**
1448 23
     * Prepare record ID to use in URL
1449 23
     * 
1450 23
     * @param mixed $id
1451 23
     * 
1452 23
     * @return string id ready for use in URL
1453 23
     */
1454 23
    public static function urlizeId($id)
1455 23
    {
1456 23
        if (is_array($id)) {
1457
            $id = rawurlencode('('.self::flexiUrl($id).')');
1458 23
        } else if (preg_match('/^ext:/', $id)) {
1459 23
            $id = self::urlEncode($id);
1460 23
        } else if (preg_match('/^code:/', $id)) {
1461 23
            $id = self::code(self::urlEncode(self::uncode($id)));
1462 23
        }
1463
        return $id;
1464
    }
1465 23
1466 23
    /**
1467
     * Test if given record ID exists in FlexiBee.
1468
     *
1469 23
     * @param mixed $identifer presence state
1470
     *
1471 23
     * @return boolean
1472 23
     */
1473
    public function idExists($identifer = null)
1474 23
    {
1475
        if (is_null($identifer)) {
1476
            $identifer = $this->getMyKey();
1477 23
        }
1478 23
        $ignorestate = $this->ignore404();
1479
        $this->ignore404(true);
1480
        $this->getFlexiData(null,
1481
            [
1482
            'detail' => 'custom:'.$this->getKeyColumn(),
1483
            $this->getKeyColumn() => $identifer
1484
        ]);
1485
        $this->ignore404($ignorestate);
1486
        return $this->lastResponseCode == 200;
1487
    }
1488
1489 65
    /**
1490
     * Test if given record exists in FlexiBee.
1491 65
     *
1492 65
     * @param array|string|int $data ext:id:23|code:ITEM|['id'=>23]|23
1493
     * 
1494
     * @return boolean Record presence status
1495 65
     */
1496 65
    public function recordExists($data = [])
1497
    {
1498
1499
        if (empty($data)) {
1500
            $data = $this->getData();
1501 65
        }
1502
        $ignorestate = $this->ignore404();
1503
        $this->ignore404(true);
1504
        $keyColumn   = $this->getKeyColumn();
1505
        $res         = $this->getColumnsFromFlexibee([$keyColumn],
1506
            is_array($data) ? $data : [$keyColumn => $data]);
1507
1508
        if (empty($res) || (isset($res['success']) && ($res['success'] == 'false'))
1509
            || ((isset($res) && is_array($res)) && !isset($res[0]) )) {
1510
            $found = false;
1511 71
        } else {
1512
            $found = true;
1513 71
        }
1514
        $this->ignore404($ignorestate);
1515
        return $found;
1516
    }
1517
1518
    /**
1519
     * Subitems - ex. items of invoice
1520
     * 
1521
     * @return array of document items or null
1522 23
     */
1523
    public function getSubItems()
1524 23
    {
1525
        return array_key_exists('polozkyFaktury', $this->getData()) ? $this->getDataValue('polozkyFaktury')
1526
                : (array_key_exists('polozkyDokladu', $this->getData()) ? $this->getDataValue('polozkyDokladu')
1527
                : null);
1528
    }
1529
1530
    /**
1531
     * Vrací z FlexiBee sloupečky podle podmínek.
1532 15
     *
1533
     * @param array|int|string $conditions pole podmínek nebo ID záznamu
1534 15
     * @param string           $indexBy    klice vysledku naplnit hodnotou ze
1535 15
     *                                     sloupečku
1536 15
     * @return array
1537 15
     */
1538 15
    public function getAllFromFlexibee($conditions = null, $indexBy = null)
1539 9
    {
1540 9
        if (is_int($conditions)) {
1541 15
            $conditions = [$this->getmyKeyColumn() => $conditions];
0 ignored issues
show
Bug introduced by
The method getmyKeyColumn() does not exist on FlexiPeeHP\FlexiBeeRO. Did you maybe mean getKeyColumn()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1541
            $conditions = [$this->/** @scrutinizer ignore-call */ getmyKeyColumn() => $conditions];

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

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

Loading history...
1542
        }
1543
1544
        $flexiData = $this->getFlexiData('', $conditions);
1545
1546
        if (!is_null($indexBy)) {
1547
            $flexiData = $this->reindexArrayBy($flexiData);
1548
        }
1549
1550 23
        return $flexiData;
1551
    }
1552 23
1553 23
    /**
1554 23
     * Vrací z FlexiBee sloupečky podle podmínek.
1555 23
     *
1556 23
     * @param string[] $columnsList seznam položek
1557 23
     * @param array    $conditions  pole podmínek nebo ID záznamu
1558 23
     * @param string   $indexBy     Sloupeček podle kterého indexovat záznamy
1559 23
     *
1560 23
     * @return array
1561 23
     */
1562 23
    public function getColumnsFromFlexibee($columnsList, $conditions = [],
1563 23
                                           $indexBy = null)
1564 23
    {
1565 23
        $detail = 'full';
1566
        switch (gettype($columnsList)) {
1567 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...
1568
                $conditions = [$this->getmyKeyColumn() => $conditions];
1569
            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...
1570
                if (!is_null($indexBy) && !array_key_exists($indexBy,
1571
                        $columnsList)) {
1572
                    $columnsList[] = $indexBy;
1573
                }
1574
                $columns = implode(',', array_unique($columnsList));
1575
                $detail  = 'custom:'.$columns;
1576
            default:
1577 22
                switch ($columnsList) {
1578
                    case 'id':
1579 22
                        $detail = 'id';
1580
                        break;
1581 21
                    case 'summary':
1582
                        $detail = 'summary';
1583
                        break;
1584
                    default:
1585
                        break;
1586
                }
1587
                break;
1588
        }
1589 22
1590
        $conditions['detail'] = $detail;
1591 22
1592 22
        $flexiData = $this->getFlexiData(null, $conditions);
1593 22
1594
        if (is_string($indexBy) && is_array($flexiData) && array_key_exists(0,
1595
                $flexiData) && array_key_exists($indexBy, $flexiData[0])) {
1596 22
            $flexiData = $this->reindexArrayBy($flexiData, $indexBy);
1597
        }
1598
1599
        return $flexiData;
1600
    }
1601
1602
    /**
1603
     * Vrací kód záznamu.
1604
     * Obtain record CODE
1605 22
     *
1606
     * @param mixed $data
1607 22
     *
1608 22
     * @return string
1609 22
     */
1610 22
    public function getKod($data = null, $unique = true)
1611 22
    {
1612 22
        $kod = null;
1613 22
1614 22
        if (is_null($data)) {
1615 22
            $data = $this->getData();
1616 22
        }
1617 22
1618 22
        if (is_string($data)) {
1619
            $data = [$this->nameColumn => $data];
1620 22
        }
1621
1622
        if (isset($data['kod'])) {
1623
            $kod = $data['kod'];
1624
        } else {
1625
            if (isset($data[$this->nameColumn])) {
1626
                $kod = preg_replace('/[^a-zA-Z0-9]/', '',
1627
                    \Ease\Sand::rip($data[$this->nameColumn]));
1628
            } else {
1629
                if (isset($data[$this->keyColumn])) {
1630
                    $kod = \Ease\Sand::rip($data[$this->keyColumn]);
1631
                }
1632 22
            }
1633
            $kod = substr($kod, 0, 20);
1634
        }
1635
1636
        if (!strlen($kod)) {
1637
            $kod = 'NOTSET';
1638
        }
1639
1640
        if (strlen($kod) > 18) {
1641 23
            $kodfinal = strtoupper(substr($kod, 0, 18));
1642
        } else {
1643 23
            $kodfinal = strtoupper($kod);
1644 23
        }
1645 23
1646 23
        if ($unique) {
1647 16
            $counter = 0;
1648 16
            if (!empty($this->codes) && count($this->codes)) {
1649 23
                foreach ($this->codes as $codesearch => $keystring) {
1650
                    if (strstr($codesearch, $kodfinal)) {
1651
                        ++$counter;
1652
                    }
1653
                }
1654
            }
1655
            if ($counter) {
1656
                $kodfinal = $kodfinal.$counter;
1657
            }
1658 23
1659
            $this->codes[$kodfinal] = $kod;
1660 23
        }
1661 23
1662 23
        return self::code($kodfinal);
1663 23
    }
1664 23
1665 23
    /**
1666 23
     * Write Operation Result.
1667 23
     *
1668 23
     * @param array  $resultData
1669
     * @param string $url        URL
1670
     * 
1671
     * @return boolean Log save success
1672
     */
1673
    public function logResult($resultData = null, $url = null)
1674
    {
1675
        $logResult = false;
1676
        if (isset($resultData['success']) && ($resultData['success'] == 'false')) {
1677 23
            if (isset($resultData['message'])) {
1678
                $this->addStatusMessage($resultData['message'], 'warning');
1679 23
            }
1680 23
            $this->addStatusMessage('Error '.$this->lastResponseCode.': '.urldecode($url),
1681 23
                'warning');
1682 23
            unset($url);
1683 23
        }
1684 23
        if (is_null($resultData)) {
1685 13
            $resultData = $this->lastResult;
1686 13
        }
1687 23
        if (isset($url)) {
1688
            $this->logger->addStatusMessage($this->lastResponseCode.':'.urldecode($url));
1689
        }
1690
1691
        if (isset($resultData['results'])) {
1692
            if ($resultData['success'] == 'false') {
1693
                $status = 'error';
1694
            } else {
1695
                $status = 'success';
1696 23
            }
1697
            foreach ($resultData['results'] as $result) {
1698 23
                if (isset($result['request-id'])) {
1699 23
                    $rid = $result['request-id'];
1700 23
                } else {
1701 23
                    $rid = '';
1702 23
                }
1703 16
                if (isset($result['errors'])) {
1704 16
                    foreach ($result['errors'] as $error) {
1705 23
                        $message = $error['message'];
1706
                        if (isset($error['for'])) {
1707
                            $message .= ' for: '.$error['for'];
1708
                        }
1709
                        if (isset($error['value'])) {
1710
                            $message .= ' value:'.$error['value'];
1711
                        }
1712
                        if (isset($error['code'])) {
1713
                            $message .= ' code:'.$error['code'];
1714 23
                        }
1715
                        $this->addStatusMessage($rid.': '.$message, $status);
1716 23
                    }
1717 23
                }
1718 23
            }
1719 23
        }
1720 23
        return $logResult;
1721 16
    }
1722 16
1723 23
    /**
1724
     * Save RAW Curl Request & Response to files in Temp directory
1725
     */
1726
    public function saveDebugFiles()
1727
    {
1728
        $tmpdir   = sys_get_temp_dir();
1729
        $fname    = $this->evidence.'-'.$this->curlInfo['when'].'.'.$this->format;
1730
        $reqname  = $tmpdir.'/request-'.$fname;
1731 23
        $respname = $tmpdir.'/response-'.$fname;
1732
        file_put_contents($reqname, $this->postFields);
1733 23
        file_put_contents($respname, $this->lastCurlResponse);
1734 1
    }
1735 1
1736 23
    /**
1737 23
     * Připraví data pro odeslání do FlexiBee
1738
     *
1739
     * @param string $data
1740
     */
1741
    public function setPostFields($data)
1742
    {
1743
        $this->postFields = $data;
1744 20
    }
1745
1746 20
    /**
1747 20
     * Get Content ready to be send as POST body
1748 20
     * @return string
1749 20
     */
1750
    public function getPostFields()
1751
    {
1752
        return $this->postFields;
1753
    }
1754
1755 20
    /**
1756
     * Generuje fragment url pro filtrování.
1757
     *
1758
     * @see https://www.flexibee.eu/api/dokumentace/ref/filters
1759
     *
1760
     * @param array  $data   key=>values; value can bee class DatePeriod
1761
     * @param string $joiner default and/or
1762
     * @param string $defop  default operator
1763
     *
1764
     * @return string
1765
     */
1766
    public static function flexiUrl(array $data, $joiner = 'and', $defop = 'eq')
1767
    {
1768
        $parts = [];
1769
1770
        foreach ($data as $column => $value) {
1771
            if (!is_numeric($column)) {
1772
                if (is_integer($data[$column]) || is_float($data[$column])) {
1773
                    $parts[$column] = $column.' eq \''.$data[$column].'\'';
1774
                } elseif (is_bool($data[$column])) {
1775
                    $parts[$column] = $data[$column] ? $column.' eq true' : $column.' eq false';
1776
                } elseif (is_null($data[$column])) {
1777
                    $parts[$column] = $column." is null";
1778
                } elseif (is_object($data[$column])) {
1779
                    switch (get_class($data[$column])) {
1780
                        case 'DatePeriod':
1781
                            $parts[$column] = $column." between '".$data[$column]->getStartDate()->format(self::$DateFormat)."' '".$data[$column]->getEndDate()->format(self::$DateFormat)."'";
1782
                            break;
1783
                        default:
1784
                            $parts[$column] = $column." $defop '".$data[$column]."'";
1785
                            break;
1786
                    }
1787
                } else {
1788
                    switch ($value) {
1789
                        case '!null':
1790
                            $parts[$column] = $column." is not null";
1791
                            break;
1792
                        case 'is empty':
1793
                        case 'is not empty':
1794
                            $parts[$column] = $column.' '.$value;
1795
                            break;
1796
                        default:
1797
                            switch (explode(' ', trim($value))[0]) {
1798
                                case 'like':
1799
                                case 'begins':
1800
                                case 'ends':
1801
                                    $parts[$column] = $column         .= ' '.$value;
1802
                                    break;
1803
                                default:
1804
                                    if ($column == 'stitky') {
1805
                                        $parts[$column] = $column."='".self::code($data[$column])."'";
1806
                                    } else {
1807
                                        $parts[$column] = $column." $defop '".$data[$column]."'";
1808
                                    }
1809
                                    break;
1810
                            }
1811
1812
                            break;
1813
                    }
1814
                }
1815
            } else {
1816
                $parts[] = $value;
1817
            }
1818
        }
1819
        return implode(' '.$joiner.' ', $parts);
1820
    }
1821
1822
    /**
1823
     * Obtain record/object numeric identificator id:
1824
     * Vrací číselný identifikátor objektu id:
1825
     *
1826
     * @link https://demo.flexibee.eu/devdoc/identifiers Identifikátory záznamů
1827
     *
1828
     * @return null|int indentifikátor záznamu reprezentovaného objektem
1829
     */
1830
    public function getRecordID()
1831
    {
1832
        $id = $this->getDataValue('id');
1833
        return is_null($id) ? null : is_numeric($id) ? intval($id) : $id;
1834
    }
1835
1836
    /**
1837
     * Obtain record/object identificator code:
1838
     * Vrací identifikátor objektu code:
1839
     *
1840
     * @link https://demo.flexibee.eu/devdoc/identifiers Identifikátory záznamů
1841
     *
1842
     * @return string record code identifier
1843
     */
1844
    public function getRecordCode()
1845 23
    {
1846
        return empty($this->getDataValue('kod')) ? null : self::code($this->getDataValue('kod'));
1847 23
    }
1848
1849
    /**
1850
     * Obtain record/object identificator extId: code: or id:
1851
     * Vrací identifikátor objektu extId: code: nebo id:
1852
     *
1853
     * @link https://demo.flexibee.eu/devdoc/identifiers Identifikátory záznamů
1854
     *
1855
     * @return string|int|null record code identifier
1856
     */
1857 23
    public function getRecordIdent()
1858
    {
1859 23
        $ident = $this->getExternalID();
1860
        if (empty($ident)) {
1861
            $ident = $this->getRecordCode();
1862
        }
1863
        if (empty($ident)) {
1864
            $ident = $this->getRecordID();
1865
        }
1866
        return $ident;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $ident also could return the type array which is incompatible with the documented return type null|integer|string.
Loading history...
1867
    }
1868
1869
    /**
1870
     * Obtain record/object identificator code: or id:
1871
     * Vrací identifikátor objektu code: nebo id:
1872
     *
1873
     * @link https://demo.flexibee.eu/devdoc/identifiers Identifikátory záznamů
1874
     * 
1875
     * @return string indentifikátor záznamu reprezentovaného objektem
1876
     */
1877
    public function __toString()
1878
    {
1879
        return strval($this->getRecordIdent());
1880
    }
1881
1882
    /**
1883
     * Gives you FlexiPeeHP class name for Given Evidence
1884
     *
1885
     * @param string $evidence
1886
     * 
1887
     * @return string Class name
1888
     */
1889
    public static function evidenceToClassName($evidence)
1890
    {
1891
        return str_replace(' ', '', ucwords(str_replace('-', ' ', $evidence)));
1892
    }
1893
1894
    /**
1895
     * Obtain ID of first record in evidence
1896
     *
1897
     * @return string|null id or null if no records
1898
     */
1899
    public function getFirstRecordID()
1900
    {
1901
        $firstID    = null;
1902
        $keyColumn  = $this->getKeyColumn();
1903
        $firstIdRaw = $this->getColumnsFromFlexibee([$keyColumn],
1904
            ['limit' => 1, 'order' => $keyColumn], $keyColumn);
1905
        if (!empty($firstIdRaw) && isset(current($firstIdRaw)[$keyColumn])) {
1906
            $firstID = current($firstIdRaw)[$keyColumn];
1907
        }
1908
        return is_numeric($firstID) ? intval($firstID) : $firstID;
1909
    }
1910
1911
    /**
1912
     * Vrací hodnotu daného externího ID
1913
     *
1914
     * @param string $want Namespace Selector. If empty,you obtain the first one.
1915
     * 
1916
     * @return string|array one id or array if multiplete
1917
     */
1918
    public function getExternalID($want = null)
1919
    {
1920
        $extid = null;
1921
        $ids   = $this->getDataValue('external-ids');
1922
        if (is_null($want)) {
1923
            if (!empty($ids)) {
1924
                $extid = current($ids);
1925
            }
1926
        } else {
1927
            if (!is_null($ids) && is_array($ids)) {
1928
                foreach ($ids as $id) {
1929
                    if (strstr($id, 'ext:'.$want)) {
1930
                        if (is_null($extid)) {
1931
                            $extid = str_replace('ext:'.$want.':', '', $id);
1932
                        } else {
1933
                            if (is_array($extid)) {
1934
                                $extid[] = str_replace('ext:'.$want.':', '', $id);
1935
                            } else {
1936
                                $extid = [$extid, str_replace('ext:'.$want.':',
1937
                                        '', $id)];
1938
                            }
1939
                        }
1940
                    }
1941
                }
1942
            }
1943
        }
1944
        return $extid;
1945
    }
1946
1947
    /**
1948
     * Obtain actual GlobalVersion
1949
     * Vrací aktuální globální verzi změn
1950
     *
1951
     * @link https://www.flexibee.eu/api/dokumentace/ref/changes-api#globalVersion Globální Verze
1952
     * 
1953
     * @return type
0 ignored issues
show
Bug introduced by
The type FlexiPeeHP\type was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
1954
     */
1955
    public function getGlobalVersion()
1956
    {
1957
        $this->getFlexiData(null, ['add-global-version' => 'true', 'limit' => 1]);
1958
1959
        return $this->globalVersion;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->globalVersion returns the type integer which is incompatible with the documented return type FlexiPeeHP\type.
Loading history...
1960
    }
1961
1962
    /**
1963
     * Gives you current ApiURL with given format suffix
1964
     * 
1965
     * @param string $format json|html|xml|...
1966
     * 
1967
     * @return string API URL for current record or object/evidence
1968
     */
1969
    public function getApiURL($format = null)
1970
    {
1971
        $apiUrl = str_replace(['.'.$this->format, '?limit=0'], '', $this->apiURL);
1972
        return $apiUrl.(empty($format) ? '' : '.'.$format );
1973
    }
1974
1975
    /**
1976
     * Obtain content type of last response
1977
     *
1978
     * @return string
1979
     */
1980
    public function getResponseFormat()
1981
    {
1982
        return $this->responseFormat;
1983
    }
1984
1985
    /**
1986
     * Return the same response format for one and multiplete results
1987
     *
1988
     * @param array $responseBody
1989
     * 
1990
     * @return array
1991
     */
1992
    public function unifyResponseFormat($responseBody)
1993
    {
1994
        if (!is_array($responseBody) || array_key_exists('message',
0 ignored issues
show
introduced by
The condition is_array($responseBody) is always true.
Loading history...
1995
                $responseBody)) { //Unifi response format
1996
            $response = $responseBody;
1997
        } else {
1998
            $evidence = $this->getResponseEvidence();
1999
            if (array_key_exists($evidence, $responseBody)) {
2000
                $response        = [];
2001
                $evidenceContent = $responseBody[$evidence];
2002
                if (array_key_exists(0, $evidenceContent)) {
2003
                    $response[$evidence] = $evidenceContent; //Multiplete Results
2004
                } else {
2005
                    $response[$evidence][0] = $evidenceContent; //One result
2006
                }
2007
            } else {
2008
                if (isset($responseBody['priloha'])) {
2009
                    $response = $responseBody['priloha'];
2010
                } else {
2011
                    if (array_key_exists('results', $responseBody)) {
2012
                        $response = $responseBody['results'];
2013
                    } else {
2014
                        $response = $responseBody;
2015
                    }
2016
                }
2017
            }
2018
        }
2019
        return $response;
2020
    }
2021
2022
    /**
2023
     * Obtain structure for current (or given) evidence
2024
     *
2025
     * @param string $evidence
2026
     * 
2027
     * @return array Evidence structure
2028
     */
2029
    public function getOfflineColumnsInfo($evidence = null)
2030
    {
2031
        $columnsInfo = null;
2032
        $infoSource  = self::$infoDir.'/Properties.'.(empty($evidence) ? $this->getEvidence()
2033
                : $evidence).'.json';
2034
        if (file_exists($infoSource)) {
2035 23
            $columnsInfo = json_decode(file_get_contents($infoSource), true);
2036
        }
2037 23
        return $columnsInfo;
2038 23
    }
2039 23
2040 23
    /**
2041
     * Obtain Current evidence Live structure
2042
     * 
2043
     * @param string $evidence
2044
     * 
2045
     * @return array structure
2046
     */
2047
    public function getOnlineColumnsInfo($evidence = null)
2048
    {
2049
        $properties = [];
2050
        $evidence   = is_null($evidence) ? $this->getEvidence() : $evidence;
2051
        $flexinfo   = $this->performRequest('/c/'.$this->company.'/'.$evidence.'/properties.json');
2052
        if (count($flexinfo) && array_key_exists('properties', $flexinfo)) {
2053
            foreach ($flexinfo['properties']['property'] as $evidenceProperty) {
2054
                $key                      = $evidenceProperty['propertyName'];
2055
                $properties[$key]         = $evidenceProperty;
2056
                $properties[$key]['name'] = $evidenceProperty['name'];
2057
                $properties[$key]['type'] = $evidenceProperty['type'];
2058
                if (array_key_exists('url', $evidenceProperty)) {
2059
                    $properties[$key]['url'] = str_replace('?limit=0', '',
2060
                        $evidenceProperty['url']);
2061
                }
2062
            }
2063
        }
2064
        return $properties;
2065
    }
2066
2067
    /**
2068
     * Update evidence info from array or online from properties.json or offline
2069
     * 
2070
     * @param array  $columnsInfo
2071
     * @param string $evidence
2072
     */
2073
    public function updateColumnsInfo($columnsInfo = null, $evidence = null)
2074
    {
2075
        $evidence = is_null($evidence) ? $this->getEvidence() : $evidence;
2076
        if (is_null($columnsInfo)) {
2077
            $this->columnsInfo[$evidence] = $this->offline ? $this->getOfflineColumnsInfo($evidence)
2078
                    : $this->getOnlineColumnsInfo($evidence);
2079
        } else {
2080
            $this->columnsInfo[$evidence] = $columnsInfo;
2081
        }
2082
    }
2083
2084
    /**
2085
     * Gives you evidence structure. You can obtain current online by pre-calling:
2086
     * $this->updateColumnsInfo($evidence, $this->getOnlineColumnsInfo($evidence));
2087
     * 
2088
     * @param string $evidence
2089
     * 
2090
     * @return array
2091
     */
2092
    public function getColumnsInfo($evidence = null)
2093
    {
2094
        $evidence = is_null($evidence) ? $this->getEvidence() : $evidence;
2095
        if (!array_key_exists($evidence, $this->columnsInfo)) {
2096
            $this->updateColumnsInfo($this->getOfflineColumnsInfo($evidence),
2097
                $evidence);
2098
        }
2099
        return $this->columnsInfo[$evidence];
2100
    }
2101
2102
    /**
2103
     * Gives you properties for (current) evidence column
2104
     *
2105
     * @param string $column    name of column
2106
     * @param string $evidence  evidence name if different
2107
     *
2108
     * @return array column properties or null if column not exits
2109
     */
2110
    public function getColumnInfo($column, $evidence = null)
2111
    {
2112
        $columnsInfo = $this->getColumnsInfo(empty($evidence) ? $this->getEvidence()
2113
                : $evidence);
2114
        return is_array($columnsInfo) ? array_key_exists($column, $columnsInfo) ? $columnsInfo[$column]
0 ignored issues
show
introduced by
The condition is_array($columnsInfo) is always true.
Loading history...
2115
                : null : null;
2116
    }
2117
2118
    /**
2119
     * Obtain actions for current (or given) evidence
2120
     *
2121
     * @param string $evidence
2122
     * 
2123
     * @return array Evidence structure
2124
     */
2125
    public function getActionsInfo($evidence = null)
2126
    {
2127
        $actionsInfo = null;
2128
        if (is_null($evidence)) {
2129
            $evidence = $this->getEvidence();
2130
        }
2131
        $propsName = lcfirst(FlexiBeeRO::evidenceToClassName($evidence));
2132
        if (isset(\FlexiPeeHP\Actions::$$propsName)) {
2133
            $actionsInfo = Actions::$$propsName;
2134
        }
2135
        return $actionsInfo;
2136
    }
2137
2138
    /**
2139
     * Obtain relations for current (or given) evidence
2140
     *
2141
     * @param string $evidence
2142
     * 
2143
     * @return array Evidence structure
2144
     */
2145
    public function getRelationsInfo($evidence = null)
2146
    {
2147
        $relationsInfo = null;
2148
        if (is_null($evidence)) {
2149
            $evidence = $this->getEvidence();
2150
        }
2151
        $propsName = lcfirst(FlexiBeeRO::evidenceToClassName($evidence));
2152
        if (isset(\FlexiPeeHP\Relations::$$propsName)) {
2153
            $relationsInfo = Relations::$$propsName;
2154
        }
2155
        return $relationsInfo;
2156
    }
2157
2158
    /**
2159
     * Obtain info for current (or given) evidence
2160
     *
2161
     * @param string $evidence
2162
     * 
2163
     * @return array Evidence info
2164
     */
2165
    public function getEvidenceInfo($evidence = null)
2166
    {
2167
        $evidencesInfo = null;
2168
        if (is_null($evidence)) {
2169
            $evidence = $this->getEvidence();
2170
        }
2171
        if (isset(EvidenceList::$evidences[$evidence])) {
2172
            $evidencesInfo = EvidenceList::$evidences[$evidence];
2173
            $propsName     = lcfirst(FlexiBeeRO::evidenceToClassName($evidence));
2174
            if (isset(Formats::$$propsName)) {
2175
                $evidencesInfo['formats'] = Formats::$$propsName;
2176
            }
2177
        }
2178
        return $evidencesInfo;
2179
    }
2180
2181
    /**
2182
     * Obtain name for current (or given) evidence path
2183
     *
2184
     * @param string $evidence Evidence Path
2185
     * 
2186
     * @return array Evidence info
2187
     */
2188
    public function getEvidenceName($evidence = null)
2189
    {
2190
        $evidenceName = null;
2191
        if (is_null($evidence)) {
2192
            $evidence = $this->getEvidence();
2193
        }
2194
        if (isset(EvidenceList::$name[$evidence])) {
2195
            $evidenceName = EvidenceList::$name[$evidence];
2196
        }
2197
        return $evidenceName;
2198
    }
2199
2200
    /**
2201
     * Save current object to file
2202
     *
2203
     * @param string $destfile path to file
2204
     */
2205
    public function saveResponseToFile($destfile)
2206
    {
2207
        if (strlen($this->lastCurlResponse)) {
2208
            $this->doCurlRequest($this->apiURL, 'GET', $this->format);
2209
        }
2210
        file_put_contents($destfile, $this->lastCurlResponse);
2211
    }
2212
2213
    /**
2214
     * Obtain established relations listing
2215
     *
2216
     * @return array Null or Relations
2217
     */
2218
    public function getVazby($id = null)
2219
    {
2220
        if (is_null($id)) {
2221
            $id = $this->getRecordID();
2222
        }
2223
        if (!empty($id)) {
2224
            $vazbyRaw = $this->getColumnsFromFlexibee(['vazby'],
2225
                ['relations' => 'vazby', 'id' => $id]);
2226
            $vazby    = array_key_exists('vazby', $vazbyRaw[0]) ? $vazbyRaw[0]['vazby']
2227
                    : null;
2228
        } else {
2229
            throw new \Exception(_('ID requied to get record relations '));
2230
        }
2231
        return $vazby;
2232
    }
2233
2234
    /**
2235
     * Gives You URL for Current Record in FlexiBee web interface
2236
     *
2237
     * @return string url
2238
     */
2239
    public function getFlexiBeeURL()
2240
    {
2241
        $parsed_url = parse_url(str_replace('.'.$this->format, '', $this->apiURL));
2242
        $scheme     = isset($parsed_url['scheme']) ? $parsed_url['scheme'].'://'
2243
                : '';
2244
        $host       = isset($parsed_url['host']) ? $parsed_url['host'] : '';
2245
        $port       = isset($parsed_url['port']) ? ':'.$parsed_url['port'] : '';
2246
        $user       = isset($parsed_url['user']) ? $parsed_url['user'] : '';
2247
        $pass       = isset($parsed_url['pass']) ? ':'.$parsed_url['pass'] : '';
2248
        $pass       = ($user || $pass) ? "$pass@" : '';
2249
        $path       = isset($parsed_url['path']) ? $parsed_url['path'] : '';
2250
        return $scheme.$user.$pass.$host.$port.$path;
2251
    }
2252
2253
    /**
2254
     * Set Record Key
2255
     *
2256
     * @param int|string $myKeyValue
2257
     * 
2258
     * @return boolean
2259
     */
2260
    public function setMyKey($myKeyValue)
2261
    {
2262
        if (substr($myKeyValue, 0, 4) == 'ext:') {
2263
            $extIds = $this->getDataValue('external-ids');
2264
            if (!empty($extIds) && count($extIds)) {
2265
                $extIds = array_combine($extIds, $extIds);
2266
            }
2267
            $extIds[$myKeyValue] = $myKeyValue;
2268
            $res                 = $this->setDataValue('external-ids', $extIds);
2269
        } else {
2270
            $res = parent::setMyKey($myKeyValue);
2271
        }
2272
        $this->updateApiURL();
2273
        return $res;
2274
    }
2275
2276
    /**
2277
     * Set or get ignore not found pages flag
2278
     *
2279
     * @param boolean $ignore set flag to
2280
     *
2281
     * @return boolean get flag state
2282
     */
2283
    public function ignore404($ignore = null)
2284
    {
2285
        if (!is_null($ignore)) {
2286
            $this->ignoreNotFound = $ignore;
2287
        }
2288
        return $this->ignoreNotFound;
2289
    }
2290
2291
    /**
2292
     * Send Document by mail
2293
     *
2294
     * @url https://www.flexibee.eu/api/dokumentace/ref/odesilani-mailem/
2295
     *
2296
     * @param string $to         Email ecipient
2297
     * @param string $subject    Email Subject
2298
     * @param string $body       Email Text
2299
     *
2300
     * @return int http response code
2301
     */
2302
    public function sendByMail($to, $subject, $body, $cc = null)
2303
    {
2304
        $this->setPostFields($body);
2305
2306
        $this->performRequest(rawurlencode($this->getRecordID()).'/odeslani-dokladu?to='.$to.'&subject='.urlencode($subject).'&cc='.$cc
2307
            , 'PUT', 'xml');
2308
2309
        return $this->lastResponseCode == 200;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->lastResponseCode == 200 returns the type boolean which is incompatible with the documented return type integer.
Loading history...
2310
    }
2311
2312
    /**
2313
     * Send all unsent Documents by eMail
2314
     *
2315
     * @url https://www.flexibee.eu/api/dokumentace/ref/odesilani-mailem/
2316
     * 
2317
     * @return int http response code
2318
     */
2319
    public function sendUnsent()
2320
    {
2321
        return $this->doCurlRequest('automaticky-odeslat-neodeslane', 'PUT',
2322
                'xml');
2323
    }
2324
2325
    /**
2326
     * FlexiBee date to PHP DateTime conversion
2327
     *
2328
     * @param string $flexidate 2017-05-26+02:00
2329
     *
2330
     * @return \DateTime | false
2331
     */
2332
    public static function flexiDateToDateTime($flexidate)
2333
    {
2334
        return \DateTime::createFromFormat(strstr($flexidate, '+') ? self::$DateFormat.'O'
2335
                    : self::$DateFormat, $flexidate)->setTime(0, 0);
2336
    }
2337
2338
    /**
2339
     * FlexiBee dateTime to PHP DateTime conversion
2340
     *
2341
     * @param string $flexidatetime 2017-09-26T10:00:53.755+02:00 or older 2017-05-19T00:00:00+02:00
2342
     *
2343
     * @return \DateTime | false
2344
     */
2345
    public static function flexiDateTimeToDateTime($flexidatetime)
2346
    {
2347
        if (strchr($flexidatetime, '.')) { //NewFormat
2348
            $format = self::$DateTimeFormat;
2349
        } else { // Old format
2350
            $format = 'Y-m-d\TH:i:s+P';
2351
        }
2352
        return \DateTime::createFromFormat($format, $flexidatetime);
2353
    }
2354
2355
    /**
2356
     * Získá dokument v daném formátu
2357
     * Obtain document in given format
2358
     *
2359
     * @link https://www.flexibee.eu/api/dokumentace/ref/pdf/ PDF Exports
2360
     *
2361
     * @param string  $format     pdf/csv/xml/json/ ...
2362
     * @param string  $reportName Template used to generate PDF
2363
     * @param string  $lang       cs|sk|en|de Template language used to generate PDF
2364
     * @param boolean $sign       sign resulting PDF by certificate ?
2365
     *
2366
     * @return string|null filename downloaded or none
2367
     */
2368
    public function getInFormat($format, $reportName = null, $lang = null,
2369
                                $sign = false)
2370
    {
2371
        $response = null;
2372
        if ($this->setFormat($format)) {
2373
            $urlParams = [];
2374
            switch ($format) {
2375
                case 'pdf':
2376
                    switch ($lang) {
2377
                        case 'cs':
2378
                        case 'sk':
2379
                        case 'en':
2380
                        case 'de':
2381
                            $urlParams['report-lang'] = $lang;
2382
                            break;
2383
                        case null:
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $lang of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
2384
                            break;
2385
                        default:
2386
                            throw new \Ease\Exception('Unknown language '.$lang.' for PDF export');
2387
                            break;
2388
                    }
2389
                    if (boolval($sign) === true) {
2390
                        $urlParams['report-sign'] = 'true';
2391
                    }
2392
                    break;
2393
                case 'html':
2394
                    $urlParams['inDesktopApp'] = 'true';
2395
                    break;
2396
            }
2397
            if (!empty($reportName)) {
2398
                $urlParams['report-name'] = $reportName;
2399
            }
2400
            if (($this->doCurlRequest(\Ease\Shared::addUrlParams($this->apiURL,
2401
                        $urlParams), 'GET') == 200)) {
2402
                $response = $this->lastCurlResponse;
2403
            }
2404
        }
2405
        return $response;
2406
    }
2407
2408
    /**
2409
     * Uloží dokument v daném formátu do složky v systému souborů
2410
     * Save document in given format to directory in filesystem
2411
     *
2412
     * @param string $format  pdf/csv/xml/json/ ...
2413
     * @param string $destDir where to put file (prefix)
2414
     * @param string $reportName Template used to generate PDF
2415
     *
2416
     * @return string|null filename downloaded or none
2417
     */
2418
    public function downloadInFormat($format, $destDir = './',
2419
                                     $reportName = null)
2420
    {
2421
        $fileOnDisk   = null;
2422
        $formatBackup = $this->format;
2423
        if ($this->setFormat($format)) {
2424
            $downloadTo = $destDir.$this->getEvidence().'_'.$this->getMyKey().'.'.$format;
2425
            if (($this->doCurlRequest(empty($reportName) ? $this->apiURL : \Ease\Shared::addUrlParams($this->apiURL,
2426
                            ['report-name' => $reportName]), 'GET') == 200) && (file_put_contents($downloadTo,
2427
                    $this->lastCurlResponse) !== false)) {
2428
                $fileOnDisk = $downloadTo;
2429
            }
2430
            $this->setFormat($formatBackup);
2431
        }
2432
        return $fileOnDisk;
2433
    }
2434
2435
    /**
2436
     * Take data for object
2437
     *
2438
     * @param array $data Data to keep
2439
     * 
2440
     * @return int number of records taken
2441
     */
2442
    public function takeData($data)
2443
    {
2444
        $result = parent::takeData($data);
2445
        if (array_key_exists($this->getKeyColumn(), $data) || array_key_exists('kod',
2446
                $data)) {
2447
            $this->updateApiURL();
2448
        }
2449
        return $result;
2450
    }
2451
2452
    /**
2453
     * Get Current Evidence reports listing
2454
     * 
2455
     * @link https://www.flexibee.eu/api/dokumentace/casto-kladene-dotazy-pro-api/vyber-reportu-do-pdf/ Výběr reportu do PDF
2456
     * 
2457
     * @return array
2458
     */
2459
    public function getReportsInfo()
2460
    {
2461
        $reports    = [];
2462
        $reportsRaw = $this->getFlexiData($this->getEvidenceURL().'/reports');
2463
        if (!empty($reportsRaw) && array_key_exists('reports', $reportsRaw) && !empty($reportsRaw['reports'])
2464
            && array_key_exists('report', $reportsRaw['reports']) &&
2465
            !empty($reportsRaw['reports']['report'])) {
2466
            if (\Ease\jQuery\Part::isAssoc($reportsRaw['reports']['report'])) {
2467
                $reports = [$reportsRaw['reports']['report']['reportId'] => $reportsRaw['reports']['report']];
2468
            } else {
2469
                $reports = self::reindexArrayBy($reportsRaw['reports']['report'],
2470
                        'reportId');
2471
            }
2472
        }
2473
        return $reports;
2474
    }
2475
2476
    /**
2477
     * Request authSessionId from current server
2478
     * 
2479
     * @link https://www.flexibee.eu/api/dokumentace/ref/login/ description
2480
     * 
2481
     * @param string $username
2482
     * @param string $password
2483
     * @param string $otp       optional onetime password
2484
     * 
2485
     * @return string authUserId or null in case of problems
2486
     */
2487
    public function requestAuthSessionID($username, $password, $otp = null)
2488
    {
2489
        $this->postFields = http_build_query(is_null($otp) ? ['username' => $username,
2490
            'password' => $password] : ['username' => $username, 'password' => $password,
2491
            'otp' => $otp]);
2492
        $response         = $this->performRequest('/login-logout/login', 'POST',
2493
            'json');
2494
        if (array_key_exists('refreshToken', $response)) {
2495
            $this->refreshToken = $response['refreshToken'];
2496
        } else {
2497
            $this->refreshToken = null;
2498
        }
2499
        return array_key_exists('authSessionId', $response) ? $response['authSessionId']
2500
                : null;
2501
    }
2502
2503
    /**
2504
     * Try to Sign in current user to FlexiBee and keep authSessionId
2505
     * 
2506
     * @return boolen sign in success
2507
     */
2508
    public function login()
2509
    {
2510
        $this->authSessionId = $this->requestAuthSessionID($this->user,
2511
            $this->password);
2512
        return $this->lastResponseCode == 200;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->lastResponseCode == 200 returns the type boolean which is incompatible with the documented return type FlexiPeeHP\boolen.
Loading history...
2513
    }
2514
2515
    /**
2516
     * End (current's user) session
2517
     * 
2518
     * 
2519
     * @link https://www.flexibee.eu/api/dokumentace/ref/logout Logout Reference
2520
     * 
2521
     * @param string $username force username to sign off
2522
     * 
2523
     * @return array server response
2524
     */
2525
    public function logout($username = null)
2526
    {
2527
        return $this->performRequest('/status/user/'.(is_null($username) ? $this->user
2528
                    : $username).'/logout', 'POST');
2529
    }
2530
2531
    /**
2532
     * Compile and send Report about Error500 to FlexiBee developers
2533
     * If FlexiBee is running on localost try also include java backtrace
2534
     *
2535
     * @param array $errorResponse result of parseError();
2536
     */
2537
    public function error500Reporter($errorResponse)
2538
    {
2539
        $ur = str_replace('/c/'.$this->company, '',
2540
            str_replace($this->url, '', $this->curlInfo['url']));
2541
        if (!array_key_exists($ur, $this->reports)) {
2542
            $tmpdir   = sys_get_temp_dir();
2543
            $myTime   = $this->curlInfo['when'];
2544
            $curlname = $tmpdir.'/curl-'.$this->evidence.'-'.$myTime.'.json';
2545
            file_put_contents($curlname,
2546
                json_encode($this->curlInfo, JSON_PRETTY_PRINT));
2547
2548
            $report = new \Ease\Mailer($this->reportRecipient,
2549
                'Error report 500 - '.$ur);
2550
2551
            $d     = dir($tmpdir);
2552
            while (false !== ($entry = $d->read())) {
2553
                if (strstr($entry, $myTime)) {
2554
                    $ext  = pathinfo($tmpdir.'/'.$entry, PATHINFO_EXTENSION);
2555
                    $mime = Formats::suffixToContentType($ext);
2556
                    $report->addFile($tmpdir.'/'.$entry,
2557
                        empty($mime) ? 'text/plain' : $mime);
2558
                }
2559
            }
2560
            $d->close();
2561
2562
            if ((strstr($this->url, '://localhost') || strstr($this->url,
2563
                    '://127.')) && file_exists('/var/log/flexibee.log')) {
2564
2565
                $fl = fopen('/var/log/'.'flexibee.log', 'r');
2566
                if ($fl) {
0 ignored issues
show
introduced by
$fl is of type resource|false, thus it always evaluated to false.
Loading history...
2567
                    $tracelog = [];
2568
                    for ($x_pos = 0, $ln = 0, $output = array(); fseek($fl,
2569
                            $x_pos, SEEK_END) !== -1; $x_pos--) {
2570
                        $char = fgetc($fl);
2571
                        if ($char === "\n") {
2572
                            $tracelog[] = $output[$ln];
2573
                            if (strstr($output[$ln], $errorResponse['message'])) {
2574
                                break;
2575
                            }
2576
                            $ln++;
2577
                            continue;
2578
                        }
2579
                        $output[$ln] = $char.((array_key_exists($ln, $output)) ? $output[$ln]
2580
                                : '');
2581
                    }
2582
2583
                    $trace     = implode("\n", array_reverse($tracelog));
2584
                    $tracefile = $tmpdir.'/trace-'.$this->evidence.'-'.$myTime.'.log';
2585
                    file_put_contents($tracefile, $trace);
2586
                    $report->addItem("\n\n".$trace);
2587
                    fclose($fl);
2588
                }
2589
            } else {
2590
                $report->addItem($errorResponse['message']);
2591
            }
2592
2593
            $licenseInfo = $this->performRequest($this->url.'/default-license.json');
2594
2595
            $report->addItem("\n\n".json_encode($licenseInfo['license'],
2596
                    JSON_PRETTY_PRINT));
2597
2598
            if ($report->send()) {
2599
                $this->reports[$ur] = $myTime;
2600
            }
2601
        }
2602
    }
2603
2604
    /**
2605
     * Returns code:CODE
2606
     *
2607
     * @param string $code
2608
     *
2609
     * @return string
2610
     */
2611
    public static function code($code)
2612
    {
2613
        return ((substr($code, 0, 4) == 'ext:') ? $code : 'code:'.strtoupper(self::uncode($code)));
2614
    }
2615
2616
    /**
2617
     * Returns CODE without code: prefix
2618
     *
2619
     * @param string $code
2620
     *
2621
     * @return string
2622
     */
2623
    public static function uncode($code)
2624
    {
2625
        return str_replace(['code:', 'code%3A'], '', $code);
2626
    }
2627
2628
    /**
2629
     * Remove all @ items from array
2630
     *
2631
     * @param array $data original data
2632
     *
2633
     * @return array data without @ columns
2634
     */
2635
    public static function arrayCleanUP($data)
2636
    {
2637
        return array_filter(
2638
            $data,
2639
            function ($key) {
2640
            return !strchr($key, '@');
2641
        }, ARRAY_FILTER_USE_KEY);
2642
    }
2643
2644
    /**
2645
     * Add Info about used user, server and libraries
2646
     *
2647
     * @param string $additions Additional note text
2648
     */
2649
    public function logBanner($additions = null)
2650
    {
2651
        $this->addStatusMessage('FlexiBee '.str_replace('://',
2652
                '://'.$this->user.'@', $this->getApiUrl()).' FlexiPeeHP v'.self::$libVersion.' (FlexiBee '.EvidenceList::$version.') EasePHP Framework v'.\Ease\Atom::$frameworkVersion.' '.$additions,
2653
            'debug');
2654
    }
2655
2656
    /**
2657
     * Reconnect After unserialization
2658
     */
2659
    public function __wakeup()
2660
    {
2661
        parent::__wakeup();
2662
        $this->curlInit();
2663
    }
2664
}
2665