Completed
Push — master ( a2b445...923447 )
by Vítězslav
05:20
created

FlexiBeeRO::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 2
eloc 6
c 2
b 0
f 1
nc 2
nop 1
dl 0
loc 10
rs 9.4285
1
<?php
2
/**
3
 * FlexiPeeHP - Třída pro čtení z FlexiBee.
4
 *
5
 * @author     Vítězslav Dvořák <[email protected]>
6
 * @copyright  (C) 2015,2016 Spoje.Net
7
 */
8
9
namespace FlexiPeeHP;
10
11
class FlexiBeeRO extends \Ease\Brick
12
{
13
    /**
14
     * Základní namespace pro komunikaci s FlexiBEE.
15
     *
16
     * @var string Jmený prostor datového bloku odpovědi
17
     */
18
    public $nameSpace = 'winstrom';
19
20
    /**
21
     * Datový blok v poli odpovědi.
22
     *
23
     * @var string
24
     */
25
    public $resultField = 'results';
26
27
    /**
28
     * Verze protokolu použitého pro komunikaci.
29
     *
30
     * @var string Verze použitého API
31
     */
32
    public $protoVersion = '1.0';
33
34
    /**
35
     * Evidence užitá objektem.
36
     *
37
     * @link https://demo.flexibee.eu/c/demo/evidence-list Přehled evidencí
38
     * @var string
39
     */
40
    public $evidence = null;
41
42
    /**
43
     * Výchozí formát pro komunikaci.
44
     *
45
     * @link https://www.flexibee.eu/api/dokumentace/ref/format-types Přehled možných formátů
46
     *
47
     * @var string json|xml|...
48
     */
49
    public $format = 'json';
50
51
    /**
52
     * Curl Handle.
53
     *
54
     * @var resource
55
     */
56
    public $curl = null;
57
58
    /**
59
     * @var type
60
     */
61
    public $company = FLEXIBEE_COMPANY;
62
63
    /**
64
     * @var string
65
     */
66
    public $url = FLEXIBEE_URL;
67
68
    /**
69
     * @var string
70
     */
71
    public $user = FLEXIBEE_LOGIN;
72
73
    /**
74
     * @var string
75
     */
76
    public $password = FLEXIBEE_PASSWORD;
77
78
    /**
79
     * @var array Pole HTTP hlaviček odesílaných s každým požadavkem
80
     */
81
    public $defaultHttpHeaders = ['User-Agent: FlexiPeeHP'];
82
83
    /**
84
     * Default additional request url parameters after question mark
85
     * 
86
     * @link https://www.flexibee.eu/api/dokumentace/ref/urls   Common params
87
     * @link https://www.flexibee.eu/api/dokumentace/ref/paging Paging params
88
     * @var array
89
     */
90
    public $defaultUrlParams = ['limit' => 0];
91
92
    /**
93
     * Identifikační řetězec.
94
     *
95
     * @var string
96
     */
97
    public $init = null;
98
99
    /**
100
     * Sloupeček s názvem.
101
     *
102
     * @var string
103
     */
104
    public $nameColumn = 'nazev';
105
106
    /**
107
     * Sloupeček obsahující datum vložení záznamu do shopu.
108
     *
109
     * @var string
110
     */
111
    public $myCreateColumn = 'false';
112
113
    /**
114
     * Slopecek obsahujici datum poslení modifikace záznamu do shopu.
115
     *
116
     * @var string
117
     */
118
    public $myLastModifiedColumn = 'lastUpdate';
119
120
    /**
121
     * Klíčový idendifikátor záznamu.
122
     *
123
     * @var string
124
     */
125
    public $fbKeyColumn = 'id';
126
127
    /**
128
     * Informace o posledním HTTP requestu.
129
     *
130
     * @var *
131
     */
132
    public $info;
133
134
    /**
135
     * Informace o poslední HTTP chybě.
136
     *
137
     * @var string
138
     */
139
    public $lastCurlError = null;
140
141
    /**
142
     * Used codes storage.
143
     *
144
     * @var array
145
     */
146
    public $codes = null;
147
148
    /**
149
     * Last Inserted ID.
150
     *
151
     * @var int
152
     */
153
    public $lastInsertedID = null;
154
155
    /**
156
     * Default Line Prefix.
157
     *
158
     * @var string
159
     */
160
    public $prefix = '/c/';
161
162
    /**
163
     * HTTP Response code of last request
164
     *
165
     * @var int
166
     */
167
    public $lastResponseCode = null;
168
169
    /**
170
     * Array of fields for next curl POST operation
171
     *
172
     * @var array
173
     */
174
    protected $postFields = [];
175
176
    /**
177
     * Last operation result data or message(s)
178
     *
179
     * @var array
180
     */
181
    public $lastResult = null;
182
183
    /**
184
     * Třída pro práci s FlexiBee.
185
     *
186
     * @param mixed $init výchozí selektor dat
187
     */
188
    public function __construct($init = null)
189
    {
190
        $this->init = $init;
191
192
        parent::__construct();
193
        $this->curlInit();
194
        if ($init) {
195
            $this->processInit($init);
196
        }
197
    }
198
199
    /**
200
     * Inicializace CURL
201
     */
202
    public function curlInit()
203
    {
204
        $this->curl = \curl_init(); // create curl resource
205
        curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); // return content as a string from curl_exec
206
        curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true); // follow redirects (compatibility for future changes in FlexiBee)
207
        curl_setopt($this->curl, CURLOPT_HTTPAUTH, true);       // HTTP authentication
208
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false); // FlexiBee by default uses Self-Signed certificates
209
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false);
210
        curl_setopt($this->curl, CURLOPT_VERBOSE, true); // For debugging
211
        curl_setopt($this->curl, CURLOPT_USERPWD,
212
            $this->user.':'.$this->password); // set username and password
213
    }
214
215
    /**
216
     * Zinicializuje objekt dle daných dat
217
     * 
218
     * @param mixed $init
219
     */
220
    public function processInit($init)
221
    {
222
        if (is_integer($init)) {
223
            $this->loadFromFlexiBee($init);
224
        } elseif (is_array($init)) {
225
            $this->takeData($init);
226
        }
227
    }
228
229
    /**
230
     * Nastaví Agendu pro Komunikaci.
231
     *
232
     * @param string $evidence
233
     */
234
    public function setEvidence($evidence)
235
    {
236
        $this->evidence = $evidence;
237
    }
238
239
    /**
240
     * Převede rekurzivně Objekt na pole.
241
     *
242
     * @param object|array $object
243
     *
244
     * @return array
245
     */
246
    public static function object2array($object)
247
    {
248
        $result = null;
249
        if (is_object($object)) {
250
            $objectData = get_object_vars($object);
251
            if (is_array($objectData) && count($objectData)) {
252
                $result = array_map('self::object2array', $objectData);
253
            }
254 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
255
            if (is_array($object)) {
256
                foreach ($object as $item => $value) {
257
                    $result[$item] = self::object2array($value);
258
                }
259
            } else {
260
                $result = $object;
261
            }
262
        }
263
264
        return $result;
265
    }
266
267
    /**
268
     * Převede rekurzivně v poli všechny objekty na jejich identifikátory.
269
     *
270
     * @param object|array $object
271
     *
272
     * @return array
273
     */
274
    public static function objectToID($object)
275
    {
276
        $result = null;
277
        if (is_object($object)) {
278
            $result = $object->__toString();
279 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
280
            if (is_array($object)) {
281
                foreach ($object as $item => $value) {
282
                    $result[$item] = self::objectToID($value);
283
                }
284
            } else { //String
285
                $result = $object;
286
            }
287
        }
288
289
        return $result;
290
    }
291
292
    /**
293
     * Funkce, která provede I/O operaci a vyhodnotí výsledek.
294
     *
295
     * @param string $urlSuffix část URL za identifikátorem firmy.
296
     * @param string $method    HTTP/REST metoda
297
     * @param string $format    Requested format
298
     * @return array|boolean Výsledek operace
299
     */
300
    public function performRequest($urlSuffix = null, $method = 'GET',
301
                                   $format = null)
302
    {
303
        if (is_null($format)) {
304
            $format = $this->format;
305
        }
306
        if (is_null($urlSuffix)) {
307
            $urlSuffix = $this->evidence.'.'.$format;
308
        }
309
        $url = $this->url.$this->prefix.$this->company.'/'.$urlSuffix;
310
        curl_setopt($this->curl, CURLOPT_URL, $url);
311
// Nastavení samotné operace
312
        curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $method);
313
//Vždy nastavíme byť i prázná postdata jako ochranu před chybou 411
314
        curl_setopt($this->curl, CURLOPT_POSTFIELDS, $this->postFields);
315
316
        $httpHeaders = $this->defaultHttpHeaders;
317
        switch ($format) {
318
            case 'json':
319
                $httpHeaders[] = 'Accept: application/json';
320
                break;
321
            case 'xml':
322
                $httpHeaders[] = 'Accept: application/xml';
323
                break;
324
        }
325
326
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, $httpHeaders);
327
328
// Proveď samotnou operaci
329
        $curlResponse = curl_exec($this->curl);
330
331
        $this->info = curl_getinfo($this->curl);
332
333
        $this->lastResponseCode = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
334
335
        if ($this->lastResponseCode != 200 && $this->lastResponseCode != 201) {
336
            $this->lastCurlError = curl_error($this->curl);
337
            switch ($format) {
338
                case 'json':
339
                    $response = preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/',
340
                        function ($match) {
341
                        return mb_convert_encoding(pack('H*', $match[1]),
342
                            'UTF-8', 'UCS-2BE');
343
                    }, $curlResponse);
344
                    $response = (json_encode(json_decode($response, true, 10),
345
                            JSON_PRETTY_PRINT));
346
                    break;
347
                case 'xml':
348
                    if (strlen($response)) {
0 ignored issues
show
Bug introduced by
The variable $response seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
349
                        $response = self::xml2array($curlResponse);
350
                    }
351
                    break;
352
            }
353
354
            if (is_array($response)) {
355
                $result = urldecode(http_build_query($response));
0 ignored issues
show
Bug introduced by
The variable $response does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
356
            } elseif (strlen($response) && ($response != 'null')) {
357
                $result = urldecode(http_build_query(self::object2array(current(json_decode($response)))));
358
            } else {
359
                $result = null;
360
            }
361
362
            if ($response == 'null') {
363
                if ($this->lastResponseCode == 200) {
364
                    $response = true;
365
                } else {
366
                    $response = null;
367
                }
368
            } else {
369
                if (is_string($response)) {
370
                    $response = self::object2array(current(json_decode($response)));
371
                }
372
            }
373
374
            if ($this->lastResponseCode == 400) {
375
                $this->logResult($response);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type boolean; however, FlexiPeeHP\FlexiBeeRO::logResult() does only seem to accept array|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
376
            } else {
377
                $this->addStatusMessage(sprintf('Error (HTTP %d): <pre>%s</pre> %s',
378
                        curl_getinfo($this->curl, CURLINFO_HTTP_CODE), $result,
379
                        $this->lastCurlError), 'error');
380
                $this->addStatusMessage($url, 'info');
381
                if (count($this->postFields)) {
382
                    $this->addStatusMessage(urldecode(http_build_query($this->postFields)),
383
                        'debug');
384
                }
385
            }
386
387
388
            return $response;
389
        }
390
391
        // Parse response
392
        switch ($format) {
393
            case 'json':
394
                $responseDecoded = json_decode($curlResponse, true, 10);
395
                if (($method == 'PUT') && isset($responseDecoded[$this->nameSpace][$this->resultField][0]['id'])) {
396
                    $this->lastInsertedID = $responseDecoded[$this->nameSpace][$this->resultField][0]['id'];
397
                } else {
398
                    $this->lastInsertedID = null;
399
                }
400
                $decodeError = json_last_error_msg();
401
                if ($decodeError != 'No error') {
402
                    $this->addStatusMessage($decodeError, 'error');
403
                }
404
                break;
405
            case 'xml':
406
                if (strlen($curlResponse)) {
407
                    $responseDecoded = self::xml2array($curlResponse);
408
                } else {
409
                    $responseDecoded = null;
410
                }
411
                break;
412
        }
413
414
        // Get response body root automatically
415
        if (isset($responseDecoded[$this->nameSpace])) {
416
            $responseDecoded = $responseDecoded[$this->nameSpace];
417
        }
418
419
        $this->lastResult = $responseDecoded;
0 ignored issues
show
Bug introduced by
The variable $responseDecoded does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Documentation Bug introduced by
It seems like $responseDecoded of type * is incompatible with the declared type array of property $lastResult.

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

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

Loading history...
420
        return $responseDecoded;
421
    }
422
423
    /**
424
     * Todo: Sem vyčlenit zpracování výsledku requestu
425
     */
426
    public function processRequest()
427
    {
428
429
    }
430
431
    /**
432
     * Convert XML to array.
433
     *
434
     * @param string $xml
435
     *
436
     * @return array
437
     */
438
    public static function xml2array($xml)
439
    {
440
        $arr = [];
441
442
        if (is_string($xml)) {
443
            $xml = simplexml_load_string($xml);
444
        }
445
446
        foreach ($xml->children() as $r) {
447
            if (count($r->children()) == 0) {
448
                $arr[$r->getName()] = strval($r);
449
            } else {
450
                $arr[$r->getName()][] = self::xml2array($r);
451
            }
452
        }
453
454
        return $arr;
455
    }
456
457
    /**
458
     * Odpojení od FlexiBee.
459
     */
460
    public function disconnect()
461
    {
462
        if (is_resource($this->curl)) {
463
            curl_close($this->curl);
464
        }
465
        $this->curl = null;
466
    }
467
468
    public function __destruct()
469
    {
470
        $this->disconnect();
471
    }
472
473
    /**
474
     * Načte data z FlexiBee.
475
     *
476
     * @param string $suffix dotaz
477
     */
478
    public function loadFlexiData($suffix = null)
479
    {
480
        return $this->takeData($this->getFlexiData($suffix));
481
    }
482
483
    /**
484
     * Načte řádek dat z FlexiBee.
485
     *
486
     * @param int $recordID id požadovaného záznamu
487
     *
488
     * @return array
489
     */
490
    public function getFlexiRow($recordID)
491
    {
492
        $record   = null;
493
        $response = $this->performRequest($this->evidence.'/'.$recordID.'.json');
494
        if (isset($response[$this->evidence])) {
495
            $record = $response[$this->evidence][0];
496
        }
497
498
        return $record;
499
    }
500
501
    /**
502
     * Načte data z FlexiBee.
503
     *
504
     * @param string $suffix     dotaz
505
     * @param string|array $conditions Volitelný filtrovací výraz
506
     */
507
    public function getFlexiData($suffix = null, $conditions = null)
508
    {
509
        $urlParams = $this->defaultUrlParams;
510
        if (!is_null($conditions)) {
511
            if (is_array($conditions)) {
512
513
                if (isset($conditions['sort'])) {
514
                    \Ease\Sand::divDataArray($conditions, $urlParams, 'sort');
515
                }
516
                if (isset($conditions['order'])) {
517
                    \Ease\Sand::divDataArray($conditions, $urlParams, 'order');
518
                }
519
                if (isset($conditions['limit'])) {
520
                    \Ease\Sand::divDataArray($conditions, $urlParams, 'limit');
521
                }
522
                if (isset($conditions['start'])) {
523
                    \Ease\Sand::divDataArray($conditions, $urlParams, 'start');
524
                }
525
                if (isset($conditions['add-row-count'])) {
526
                    \Ease\Sand::divDataArray($conditions, $urlParams,
527
                        'add-row-count');
528
                }
529
530
                $conditions = $this->flexiUrl($conditions);
531
            }
532
533
            if (strlen($conditions) && ($conditions[0] != '/')) {
534
                $conditions = '/'.rawurlencode('('.($conditions).')');
535
            }
536
        } else {
537
            $conditions = '';
538
        }
539
        if ($suffix) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $suffix of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
540
            $transactions = $this->performRequest($this->evidence.$conditions.'.'.$this->format.'?'.$suffix.'&'.http_build_query($urlParams),
541
                'GET');
542
        } else {
543
            $transactions = $this->performRequest($this->evidence.$conditions.'.'.$this->format.'?'.http_build_query($urlParams),
544
                'GET');
545
        }
546
        if (isset($transactions[$this->evidence])) {
547
            $result = $transactions[$this->evidence];
548
        } else {
549
            $result = $transactions;
550
        }
551
552
        return $result;
553
    }
554
555
    /**
556
     * Načte záznam z FlexiBee.
557
     *
558
     * @param int $id ID záznamu
559
     *
560
     * @return int počet načtených položek
561
     */
562
    public function loadFromFlexiBee($id = null)
563
    {
564
        $data = [];
565
        if (is_null($id)) {
566
            $id = $this->getMyKey();
567
        }
568
569
        $flexidata = $this->getFlexiData(null, '/'.$id);
570
        if (count($flexidata) == 1) {
571
            $data = current($flexidata);
572
        }
573
        return $this->takeData($data);
574
    }
575
576
    /**
577
     * Převede data do Json formátu pro FlexiBee.
578
     *
579
     * @param array $data
580
     *
581
     * @return string
582
     */
583
    public function jsonizeData($data)
584
    {
585
        $jsonize = [
586
            $this->nameSpace => [
587
                '@version' => $this->protoVersion,
588
                $this->evidence => $this->objectToID($data),
589
            ],
590
        ];
591
592
        return json_encode($jsonize);
593
    }
594
595
    /**
596
     * Test if given record ID exists in FlexiBee.
597
     *
598
     * @param string|int $identifer
599
     */
600
    public function idExists($identifer = null)
601
    {
602
        if (is_null($identifer)) {
603
            $identifer = $this->getMyKey();
604
        }
605
        $flexiData = $this->getFlexiData(
606
            'detail=custom:'.$this->getmyKeyColumn(), $identifer);
607
608
        return $flexiData;
609
    }
610
611
    /**
612
     * Test if given record exists in FlexiBee.
613
     *
614
     * @param array $data
615
     */
616
    public function recordExists($data = null)
617
    {
618
        if (is_null($data)) {
619
            $data = $this->getData();
620
        }
621
622
        $res = $this->getColumnsFromFlexibee([$this->myKeyColumn],
623
            self::flexiUrl($data));
0 ignored issues
show
Documentation introduced by
self::flexiUrl($data) is of type string, but the function expects a array|null.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
624
625
        return $res;
626
    }
627
628
    /**
629
     * Vrací z FlexiBee sloupečky podle podmínek.
630
     *
631
     * @param array|int|string $conditions pole podmínek nebo ID záznamu
632
     * @param string           $indexBy    klice vysledku naplnit hodnotou ze
633
     *                                     sloupečku
634
     * @return array
635
     */
636
    public function getAllFromFlexibee($conditions = null, $indexBy = null)
637
    {
638
        if (is_int($conditions)) {
639
            $conditions = [$this->getmyKeyColumn() => $conditions];
640
        }
641
642
        $flexiData = $this->getFlexiData('', $conditions);
643
644
        if ($indexBy) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $indexBy of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
645
            $flexiData = $this->reindexArrayBy($flexiData);
0 ignored issues
show
Bug introduced by
The method reindexArrayBy() does not seem to exist on object<FlexiPeeHP\FlexiBeeRO>.

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...
646
        }
647
648
        return $flexiData;
649
    }
650
651
    /**
652
     * Vrací z FlexiBee sloupečky podle podmínek.
653
     *
654
     * @param string[] $columnsList seznam položek
655
     * @param array    $conditions  pole podmínek nebo ID záznamu
656
     * @param string   $indexBy     Sloupeček podle kterého indexovat záznamy
657
     *
658
     * @return array
659
     */
660
    public function getColumnsFromFlexibee($columnsList, $conditions = null,
661
                                           $indexBy = null)
662
    {
663
        if (($columnsList != '*') && !count($columnsList)) {
664
            $this->error('getColumnsFromFlexiBee: Missing ColumnList');
665
666
            return;
667
        }
668
669
        if (is_int($conditions)) {
670
            $conditions = [$this->getmyKeyColumn() => $conditions];
671
        }
672
673
        if (is_array($columnsList)) {
674
            $columns = implode(',', array_unique($columnsList));
675
        } else {
676
            $columns = $columnsList;
677
        }
678
679
        $flexiData = $this->getFlexiData('detail=custom:'.$columns, $conditions);
680
681
        if ($indexBy) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $indexBy of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
682
            $flexiData = $this->reindexArrayBy($flexiData, $indexBy);
0 ignored issues
show
Bug introduced by
The method reindexArrayBy() does not seem to exist on object<FlexiPeeHP\FlexiBeeRO>.

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...
683
        }
684
685
        return $flexiData;
686
    }
687
688
    /**
689
     * Vrací kód záznamu.
690
     *
691
     * @param mixed $data
692
     *
693
     * @todo papat i string
694
     *
695
     * @return string
696
     */
697
    public function getKod($data = null, $unique = true)
698
    {
699
        $kod = null;
700
701
        if (is_null($data)) {
702
            $data = $this->getData();
703
        }
704
705
        if (is_string($data)) {
706
            $data = [$this->nameColumn => $data];
707
        }
708
709
        if (isset($data['kod'])) {
710
            $kod = $data['kod'];
711
        } else {
712
            if (isset($data[$this->nameColumn])) {
713
                $kod = preg_replace('/[^a-zA-Z0-9]/', '',
714
                    \Ease\Sand::rip($data[$this->nameColumn]));
715
            } else {
716
                if (isset($data[$this->myKeyColumn])) {
717
                    $kod = \Ease\Sand::rip($data[$this->myKeyColumn]);
718
                }
719
            }
720
        }
721
722
        if (!strlen($kod)) {
723
            $kod = 'NOTSET';
724
        }
725
726
        if (strlen($kod) > 18) {
727
            $kodfinal = strtoupper(substr($kod, 0, 18));
728
        } else {
729
            $kodfinal = strtoupper($kod);
730
        }
731
732
        if ($unique) {
733
            $counter = 0;
734
            if (count($this->codes)) {
735
                foreach ($this->codes as $codesearch => $keystring) {
736
                    if (strstr($codesearch, $kodfinal)) {
737
                        ++$counter;
738
                    }
739
                }
740
            }
741
            if ($counter) {
742
                $kodfinal = $kodfinal.$counter;
743
            }
744
745
            $this->codes[$kodfinal] = $kod;
746
        }
747
748
        return $kodfinal;
749
    }
750
751
    /**
752
     * Vyhledavani v záznamech objektu FlexiBee.
753
     *
754
     * @param string $what hledaný výraz
755
     *
756
     * @return array pole výsledků
757
     */
758
    public function searchString($what)
759
    {
760
        $results   = [];
761
        $conds     = [];
762
        $columns[] = $this->myKeyColumn;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$columns was never initialized. Although not strictly required by PHP, it is generally a good practice to add $columns = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
763
        foreach ($this->useKeywords as $keyword => $keywordInfo) {
0 ignored issues
show
Bug introduced by
The property useKeywords does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
764
            if (isset($this->keywordsInfo[$keyword]['virtual']) && ($this->keywordsInfo[$keyword]['virtual']
0 ignored issues
show
Bug introduced by
The property keywordsInfo does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
765
                == true)) {
766
                if ($keyword == $this->nameColumn) {
767
                    $this->nameColumn = $this->myKeyColumn;
768
                }
769
                continue;
770
            }
771
            switch ($keywordInfo) {
772
                case 'INT':
773 View Code Duplication
                case 'FLOAT':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
774
                    if (is_numeric($what)) {
775
                        $conds[]   = "($keyword = ".$what.')';
776
                        $columns[] = "$keyword";
777
                    }
778
                    break;
779
                case 'TEXT':
780 View Code Duplication
                case 'STRING':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
781
                    if (is_string($what)) {
782
                        $conds[]   = "( $keyword like '".$what."')";
783
                        $columns[] = "$keyword";
784
                    }
785
                    break;
786
                default:
787
                    break;
788
            }
789
        }
790
791
//        $res = \Ease\Shared::db()->queryToArray('SELECT ' . implode(',', $columns) . ',' . $this->nameColumn . ' FROM ' . $this->myTable . ' WHERE ' . implode(' OR ', $conds) . ' ORDER BY ' . $this->nameColumn, $this->myKeyColumn);
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
792
793
        $res = $this->getColumnsFromFlexibee($columns, implode(' or ', $conds));
0 ignored issues
show
Documentation introduced by
implode(' or ', $conds) is of type string, but the function expects a array|null.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
794
795
        foreach ($res as $result) {
796
            $occurences = '';
797
            foreach ($result as $key => $value) {
798
                if (is_array($value)) {
799
                    continue;
800
                }
801
                if (mb_stristr($value, $what)) {
802
                    $occurences .= '('.$key.': '.$value.')';
803
                }
804
            }
805
            $results[$result[$this->myKeyColumn]] = [$this->nameColumn => $result[$this->nameColumn],
806
                'what' => $occurences,];
807
        }
808
        return $results;
809
    }
810
811
    /**
812
     * Write Operation Result.
813
     *
814
     * @param array  $resultData
815
     * @param string $url        URL
816
     */
817
    public function logResult($resultData = null, $url = null)
818
    {
819
        if (is_null($resultData)) {
820
            $resultData = $this->lastResult;
821
        }
822
        if ($url) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $url of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
823
            $this->logger->addStatusMessage($url);
824
        }
825
826
        if (isset($resultData['results'])) {
827
            $status = null;
0 ignored issues
show
Unused Code introduced by
$status is not used, you could remove the assignment.

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

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

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

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

Loading history...
828
            if ($resultData['success'] == 'false') {
829
                $status = 'error';
830
            } else {
831
                $status = 'success';
832
            }
833
            foreach ($resultData['results'] as $result) {
834
                if (isset($result['request-id'])) {
835
                    $rid = $result['request-id'];
836
                } else {
837
                    $rid = '';
838
                }
839
                if (isset($result['errors'])) {
840
                    foreach ($result['errors'] as $error) {
841
                        $message = $error['message'];
842
                        if (isset($error['for'])) {
843
                            $message .= ' for: '.$error['for'];
844
                        }
845
                        if (isset($error['value'])) {
846
                            $message .= ' value:'.$error['value'];
847
                        }
848
                        if (isset($error['code'])) {
849
                            $message .= ' code:'.$error['code'];
850
                        }
851
                        $this->logger->addStatusMessage($rid.': '.$message,
852
                            $status);
853
                    }
854
                }
855
            }
856
        }
857
        if (is_object($this->logger)) {
858
            $this->logger->flush(get_class($this));
0 ignored issues
show
Bug introduced by
The method flush() does not seem to exist on object<Ease\Logger>.

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...
859
        }
860
    }
861
862
    /**
863
     * Generuje fragment url pro filtrování.
864
     *
865
     * @see https://www.flexibee.eu/api/dokumentace/ref/filters
866
     *
867
     * @param array  $data
868
     * @param string $operator default and/or
869
     *
870
     * @return string
871
     */
872
    public static function flexiUrl(array $data, $operator = 'and')
873
    {
874
        $flexiUrl = '';
0 ignored issues
show
Unused Code introduced by
$flexiUrl is not used, you could remove the assignment.

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

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

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

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

Loading history...
875
        $parts    = [];
876
877
        foreach ($data as $column => $value) {
878
            if (is_integer($data[$column]) || is_float($data[$column])) {
879
                $parts[$column] = $column.' eq '.$data[$column];
880
            } elseif (is_bool($data[$column])) {
881
                $parts[$column] = $data[$column] ? $column.' eq true' : $column.' eq false';
882
            } elseif (is_null($data[$column])) {
883
                $parts[$column] = $column." is null";
884
            } elseif ($value == '!null') {
885
                $parts[$column] = $column." is not null";
886
            } else {
887
                $parts[$column] = $column." eq '".$data[$column]."'";
888
            }
889
        }
890
891
        $flexiUrl = implode(' '.$operator.' ', $parts);
892
893
        return $flexiUrl;
894
    }
895
896
    /**
897
     * Vrací identifikátor objektu code: nebo id:
898
     *
899
     * @link https://demo.flexibee.eu/devdoc/identifiers Identifikátory záznamů
900
     * @return string indentifikátor záznamu reprezentovaného objektem
901
     * @throws Exception data objektu neobsahují kód nebo id
902
     */
903
    public function __toString()
904
    {
905
        $myCode = $this->getDataValue('kod');
906
        if ($myCode) {
907
            $id = 'code:'.$myCode;
908
        } else {
909
            $id = $this->getDataValue('id');
910
            if (!$id) {
911
                throw new \Exception(_('invoice without loaded code: or id: cannot match with statement!'));
912
            }
913
        }
914
        return $id;
915
    }
916
}