Completed
Push — master ( fea5ff...68f225 )
by Vítězslav
04:39
created

FlexiBeeRO   D

Complexity

Total Complexity 106

Size/Duplication

Total Lines 773
Duplicated Lines 3.36 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 26
loc 773
rs 4.4444
wmc 106
lcom 1
cbo 2

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A curlInit() 0 12 1
A setEvidence() 0 4 1
B object2array() 0 20 6
F performRequest() 0 104 21
A xml2array() 0 19 4
A disconnect() 0 7 2
A __destruct() 0 4 1
A loadFlexiData() 0 4 1
A getFlexiRow() 0 10 2
B getFlexiData() 0 24 5
A loadFromFlexiBee() 0 8 2
A jsonizeData() 0 11 1
A idExists() 0 10 2
A recordExists() 0 11 2
A getAllFromFlexibee() 7 19 4
C getColumnsFromFlexibee() 7 32 7
D getKod() 0 53 13
C searchString() 12 53 15
C logResult() 0 41 12
A flexiUrl() 0 17 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

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

Common duplication problems, and corresponding solutions are:

Complex Class

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

Complex classes like FlexiBeeRO often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FlexiBeeRO, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * FlexiPeeHP - 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
     * Identifikační řetězec.
80
     *
81
     * @var string
82
     */
83
    public $init = null;
84
85
    /**
86
     * Sloupeček s názvem.
87
     *
88
     * @var string
89
     */
90
    public $nameColumn = 'nazev';
91
92
    /**
93
     * Sloupeček obsahující datum vložení záznamu do shopu.
94
     *
95
     * @var string
96
     */
97
    public $myCreateColumn = 'false';
98
99
    /**
100
     * Slopecek obsahujici datum poslení modifikace záznamu do shopu.
101
     *
102
     * @var string
103
     */
104
    public $myLastModifiedColumn = 'lastUpdate';
105
106
    /**
107
     * Klíčový idendifikátor záznamu.
108
     *
109
     * @var string
110
     */
111
    public $fbKeyColumn = 'id';
112
113
    /**
114
     * Informace o posledním HTTP requestu.
115
     *
116
     * @var array
117
     */
118
    public $info;
119
120
    /**
121
     * Informace o poslední HTTP chybě.
122
     *
123
     * @var array
124
     */
125
    public $error;
126
127
    /**
128
     * Used codes storage.
129
     *
130
     * @var array
131
     */
132
    public $codes = null;
133
134
    /**
135
     * Last Inserted ID.
136
     *
137
     * @var int
138
     */
139
    public $lastInsertedID = null;
140
141
    /**
142
     * Default Line Prefix.
143
     *
144
     * @var string
145
     */
146
    public $prefix = '/c/';
147
148
    /**
149
     * HTTP Response code of last request
150
     * 
151
     * @var int
152
     */
153
    public $lastResponseCode = null;
154
155
    /**
156
     * Array of fields for next curl POST operation
157
     * 
158
     * @var array
159
     */
160
    protected $postFields = [];
161
162
    /**
163
     * Třída pro práci s FlexiBee.
164
     *
165
     * @param string $init výchozí selektor dat
166
     */
167
    public function __construct($init = null)
168
    {
169
        $this->init = $init;
170
171
        parent::__construct();
172
        $this->curlInit();
173
    }
174
175
    public function curlInit()
176
    {
177
        $this->curl = \curl_init(); // create curl resource
178
        curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); // return content as a string from curl_exec
179
        curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true); // follow redirects (compatibility for future changes in FlexiBee)
180
        curl_setopt($this->curl, CURLOPT_HTTPAUTH, true);       // HTTP authentication
181
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false); // FlexiBee by default uses Self-Signed certificates
182
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false);
183
        curl_setopt($this->curl, CURLOPT_VERBOSE, true); // For debugging
184
        curl_setopt($this->curl, CURLOPT_USERPWD,
185
            $this->user.':'.$this->password); // set username and password
186
    }
187
188
    /**
189
     * Nastaví Agendu pro Komunikaci.
190
     *
191
     * @param string $evidence
192
     */
193
    public function setEvidence($evidence)
194
    {
195
        $this->evidence = $evidence;
196
    }
197
198
    /**
199
     * Převede rekurzivně Objekt na pole.
200
     *
201
     * @param object|array $object
202
     *
203
     * @return array
204
     */
205
    public static function object2array($object)
206
    {
207
        $result = null;
208
        if (is_object($object)) {
209
            $objectData = get_object_vars($object);
210
            if (is_array($objectData) && count($objectData)) {
211
                $result = array_map('self::object2array', $objectData);
212
            }
213
        } else {
214
            if (is_array($object)) {
215
                foreach ($object as $item => $value) {
216
                    $result[$item] = self::object2array($value);
217
                }
218
            } else {
219
                $result = $object;
220
            }
221
        }
222
223
        return $result;
224
    }
225
226
    /**
227
     * Funkce, která provede I/O operaci a vyhodnotí výsledek.
228
     *
229
     * @param string $urlSuffix část URL za identifikátorem firmy.
230
     * @param string $method    HTTP/REST metoda
231
     * @param string $format    Requested format
232
     */
233
    public function performRequest($urlSuffix = null, $method = 'GET',
234
                                   $format = null)
235
    {
236
        if (is_null($format)) {
237
            $format = $this->format;
238
        }
239
        if (is_null($urlSuffix)) {
240
            $urlSuffix = $this->evidence.'.'.$format;
241
        }
242
        $url = $this->url.$this->prefix.$this->company.'/'.$urlSuffix;
243
        curl_setopt($this->curl, CURLOPT_URL, $url);
244
// Nastavení samotné operace
245
        curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $method);
246
//Vždy nastavíme byť i prázná postdata jako ochranu před chybou 411
247
        curl_setopt($this->curl, CURLOPT_POSTFIELDS, $this->postFields);
248
249
250
// Proveď samotnou operaci
251
        $response = curl_exec($this->curl);
252
253
        $this->info = curl_getinfo($this->curl);
0 ignored issues
show
Documentation Bug introduced by
It seems like curl_getinfo($this->curl) of type * is incompatible with the declared type array of property $info.

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...
254
255
        $this->lastResponseCode = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
256
257
        if ($this->lastResponseCode != 200 && $this->lastResponseCode != 201) {
258
            $this->error = curl_error($this->curl);
0 ignored issues
show
Documentation Bug introduced by
It seems like curl_error($this->curl) of type string is incompatible with the declared type array of property $error.

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...
259
            switch ($format) {
260
                case 'json':
261
                    $response = preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/',
262
                        function ($match) {
263
                        return mb_convert_encoding(pack('H*', $match[1]),
264
                            'UTF-8', 'UCS-2BE');
265
                    }, $response);
266
                    $response = (json_encode(json_decode($response, true, 10),
267
                            JSON_PRETTY_PRINT));
268
                    break;
269
                case 'xml':
270
                    if (strlen($response)) {
271
                        $response = self::xml2array($response);
272
                    }
273
                    break;
274
            }
275
276
            if (is_array($response)) {
277
                $result = urldecode(http_build_query($response));
278
            } elseif (strlen($response) && ($response != 'null')) {
279
                $result = urldecode(http_build_query(self::object2array(current(json_decode($response)))));
280
            } else {
281
                $result = null;
282
            }
283
284
            if ($this->lastResponseCode == 400) {
285
                $this->logResult($result);
0 ignored issues
show
Documentation introduced by
$result is of type string|null, but the function expects a array.

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...
286
            } else {
287
                $this->addStatusMessage(sprintf('Error (HTTP %d): <pre>%s</pre> %s',
288
                        curl_getinfo($this->curl, CURLINFO_HTTP_CODE), $result,
289
                        $this->error), 'error');
290
                $this->addStatusMessage($url, 'info');
291
                $this->addStatusMessage(urldecode(http_build_query($this->postFields)),
292
                    'debug');
293
            }
294
            if ($response == 'null') {
295
                if ($this->lastResponseCode == 200) {
296
                    $response = true;
297
                } else {
298
                    $response = null;
299
                }
300
            } else {
301
                if (is_string($response)) {
302
                    $response = self::object2array(current(json_decode($response)));
303
                }
304
            }
305
            return $response;
306
        }
307
308
        // Parse response
309
        switch ($format) {
310
            case 'json':
311
                $decoded = json_decode($response, true, 10);
312
                if (($method == 'PUT') && isset($decoded[$this->nameSpace][$this->resultField][0]['id'])) {
313
                    $this->lastInsertedID = $decoded[$this->nameSpace][$this->resultField][0]['id'];
314
                } else {
315
                    $this->lastInsertedID = null;
316
                }
317
//                $decodeError = json_last_error_msg();
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% 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...
318
//                $this->addStatusMessage($decodeError);
319
320
                break;
321
            case 'xml':
322
                if (strlen($response)) {
323
                    $decoded = self::xml2array($response);
324
                } else {
325
                    $decoded = null;
326
                }
327
                break;
328
        }
329
330
        // Get response body root automatically
331
        if (isset($decoded[$this->nameSpace])) {
332
            $decoded = $decoded[$this->nameSpace];
333
        }
334
335
        return $decoded;
0 ignored issues
show
Bug introduced by
The variable $decoded 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...
336
    }
337
338
    /**
339
     * Convert XML to array.
340
     * 
341
     * @param string $xml
342
     *
343
     * @return array
344
     */
345
    public static function xml2array($xml)
346
    {
347
        $arr = [];
348
349
        if (is_string($xml)) {
350
            $xml = simplexml_load_string($xml);
351
        }
352
353
        foreach ($xml->children() as $r) {
354
            $t = [];
0 ignored issues
show
Unused Code introduced by
$t 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...
355
            if (count($r->children()) == 0) {
356
                $arr[$r->getName()] = strval($r);
357
            } else {
358
                $arr[$r->getName()][] = self::xml2array($r);
359
            }
360
        }
361
362
        return $arr;
363
    }
364
365
    /**
366
     * Odpojení od FlexiBee.
367
     */
368
    public function disconnect()
369
    {
370
        if (is_resource($this->curl)) {
371
            curl_close($this->curl);
372
        }
373
        $this->curl = null;
374
    }
375
376
    public function __destruct()
377
    {
378
        $this->disconnect();
379
    }
380
381
    /**
382
     * Načte data z FlexiBee.
383
     *
384
     * @param string $suffix dotaz
385
     */
386
    public function loadFlexiData($suffix = null)
387
    {
388
        return $this->takeData($this->getFlexiData($suffix));
389
    }
390
391
    /**
392
     * Načte řádek dat z FlexiBee.
393
     *
394
     * @param int $recordID id požadovaného záznamu
395
     *
396
     * @return array
397
     */
398
    public function getFlexiRow($recordID)
399
    {
400
        $record   = null;
401
        $response = $this->performRequest($this->evidence.'/'.$recordID.'.json');
402
        if (isset($response[$this->evidence])) {
403
            $record = $response[$this->evidence][0];
404
        }
405
406
        return $record;
407
    }
408
409
    /**
410
     * Načte data z FlexiBee.
411
     *
412
     * @param string $suffix     dotaz
413
     * @param string $conditions Volitelný filtrovací výraz
414
     */
415
    public function getFlexiData($suffix = null, $conditions = null)
416
    {
417
        if (!is_null($conditions)) {
418
            if ($conditions[0] != '/') {
419
                $conditions = '/'.rawurlencode('('.($conditions).')');
420
            }
421
        } else {
422
            $conditions = '';
423
        }
424
        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...
425
            $transactions = $this->performRequest($this->evidence.$conditions.'.'.$this->format.'?'.$suffix,
426
                'GET');
427
        } else {
428
            $transactions = $this->performRequest($this->evidence.$conditions.'.'.$this->format,
429
                'GET');
430
        }
431
        if (isset($transactions[$this->evidence])) {
432
            $result = $transactions[$this->evidence];
433
        } else {
434
            $result = $transactions;
435
        }
436
437
        return $result;
438
    }
439
440
    /**
441
     * Načte záznam z FlexiBee.
442
     *
443
     * @param int $id ID záznamu
444
     *
445
     * @return int počet načtených položek
446
     */
447
    public function loadFromFlexiBee($id = null)
448
    {
449
        if (is_null($id)) {
450
            $id = $this->getMyKey();
451
        }
452
453
        return $this->takeData($this->getFlexiData('/'.$id));
454
    }
455
456
    /**
457
     * Převede data do Json formátu pro FlexiBee.
458
     *
459
     * @param array $data
460
     *
461
     * @return string
462
     */
463
    public function jsonizeData($data)
464
    {
465
        $jsonize = [
466
            $this->nameSpace => [
467
                '@version' => $this->protoVersion,
468
                $this->evidence => $data,
469
            ],
470
        ];
471
472
        return json_encode($jsonize);
473
    }
474
475
    /**
476
     * Test if given record ID exists in FlexiBee.
477
     *
478
     * @param string|int $identifer
479
     */
480
    public function idExists($identifer = null)
481
    {
482
        if (is_null($identifer)) {
483
            $identifer = $this->getMyKey();
484
        }
485
        $flexiData = $this->getFlexiData(
486
            'detail=custom:'.$this->getmyKeyColumn(), $identifer);
487
488
        return $flexiData;
489
    }
490
491
    /**
492
     * Test if given record exists in FlexiBee.
493
     *
494
     * @param array $data
495
     */
496
    public function recordExists($data = null)
497
    {
498
        if (is_null($data)) {
499
            $data = $this->getData();
500
        }
501
502
        $res = $this->getColumnsFromFlexibee([$this->myKeyColumn],
503
            self::flexiUrl($data));
504
505
        return $res;
506
    }
507
508
    /**
509
     * Vrací z FlexiBee sloupečky podle podmínek.
510
     *
511
     * @param array|int|string $conditions pole podmínek nebo ID záznamu
512
     * @param array|string     $orderBy    třídit dle
513
     * @param string           $indexBy    klice vysledku naplnit hodnotou ze
514
     *                                     sloupečku
515
     * @param int              $limit      maximální počet vrácených záznamů
516
     *
517
     * @return array
518
     */
519
    public function getAllFromFlexibee($conditions = null, $orderBy = null,
0 ignored issues
show
Unused Code introduced by
The parameter $orderBy is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
520
                                       $indexBy = null, $limit = null)
0 ignored issues
show
Unused Code introduced by
The parameter $limit is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
521
    {
522
        if (is_int($conditions)) {
523
            $conditions = [$this->getmyKeyColumn() => $conditions];
524
        }
525
526
        $flexiData = $this->getFlexiData('', $conditions);
0 ignored issues
show
Bug introduced by
It seems like $conditions can also be of type array; however, FlexiPeeHP\FlexiBeeRO::getFlexiData() does only seem to accept string|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...
527
528 View Code Duplication
        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...
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...
529
            $flexiData2 = [];
530
            foreach ($flexiData as $dataID => $data) {
531
                $flexiData2[$data[$indexBy]] = $data;
532
            }
533
            $flexiData = $flexiData2;
534
        }
535
536
        return $flexiData;
537
    }
538
539
    /**
540
     * Vrací z FlexiBee sloupečky podle podmínek.
541
     *
542
     * @param string[]         $columnsList seznam položek
543
     * @param array|int|string $conditions  pole podmínek nebo ID záznamu
544
     * @param array|string     $orderBy     třídit dle
545
     * @param string           $indexBy     klice vysledku naplnit hodnotou ze
546
     *                                      sloupečku
547
     * @param int              $limit       maximální počet vrácených záznamů
548
     *
549
     * @return array
550
     */
551
    public function getColumnsFromFlexibee($columnsList, $conditions = null,
552
                                           $orderBy = null, $indexBy = null,
0 ignored issues
show
Unused Code introduced by
The parameter $orderBy is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
553
                                           $limit = null)
0 ignored issues
show
Unused Code introduced by
The parameter $limit is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
554
    {
555
        if (($columnsList != '*') && !count($columnsList)) {
556
            $this->error('getColumnsFromFlexiBee: Missing ColumnList');
557
558
            return;
559
        }
560
561
        if (is_int($conditions)) {
562
            $conditions = [$this->getmyKeyColumn() => $conditions];
563
        }
564
565
        if (is_array($columnsList)) {
566
            $columns = implode(',', array_unique($columnsList));
567
        } else {
568
            $columns = $columnsList;
569
        }
570
571
        $flexiData = $this->getFlexiData('detail=custom:'.$columns, $conditions);
0 ignored issues
show
Bug introduced by
It seems like $conditions can also be of type array; however, FlexiPeeHP\FlexiBeeRO::getFlexiData() does only seem to accept string|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...
572
573 View Code Duplication
        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...
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...
574
            $flexiData2 = [];
575
            foreach ($flexiData as $dataID => $data) {
576
                $flexiData2[$data[$indexBy]] = $data;
577
            }
578
            $flexiData = $flexiData2;
579
        }
580
581
        return $flexiData;
582
    }
583
584
    /**
585
     * Vrací kód záznamu.
586
     *
587
     * @param mixed $data
588
     *
589
     * @todo papat i string
590
     *
591
     * @return string
592
     */
593
    public function getKod($data = null, $unique = true)
594
    {
595
        $kod = null;
596
597
        if (is_null($data)) {
598
            $data = $this->getData();
599
        }
600
601
        if (is_string($data)) {
602
            $data = [$this->nameColumn => $data];
603
        }
604
605
        if (isset($data['kod'])) {
606
            $kod = $data['kod'];
607
        } else {
608
            if (isset($data[$this->nameColumn])) {
609
                $kod = preg_replace('/[^a-zA-Z0-9]/', '',
610
                    \Ease\Sand::rip($data[$this->nameColumn]));
611
            } else {
612
                if (isset($data[$this->myKeyColumn])) {
613
                    $kod = \Ease\Sand::rip($data[$this->myKeyColumn]);
614
                }
615
            }
616
        }
617
618
        if (!strlen($kod)) {
619
            $kod = 'NOTSET';
620
        }
621
622
        if (strlen($kod) > 18) {
623
            $kodfinal = strtoupper(substr($kod, 0, 18));
624
        } else {
625
            $kodfinal = strtoupper($kod);
626
        }
627
628
        if ($unique) {
629
            $counter = 0;
630
            if ($this->codes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->codes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
631
                foreach ($this->codes as $codesearch => $keystring) {
632
                    if (strstr($codesearch, $kodfinal)) {
633
                        ++$counter;
634
                    }
635
                }
636
            }
637
            if ($counter) {
638
                $kodfinal = $kodfinal.$counter;
639
            }
640
641
            $this->codes[$kodfinal] = $kod;
642
        }
643
644
        return $kodfinal;
645
    }
646
647
    /**
648
     * Vyhledavani v záznamech objektu FlexiBee.
649
     *
650
     * @param string $what hledaný výraz
651
     *
652
     * @return array pole výsledků
653
     */
654
    public function searchString($what)
655
    {
656
        $results   = [];
657
        $conds     = [];
658
        $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...
659
        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...
660
            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...
661
                == true)) {
662
                if ($keyword == $this->nameColumn) {
663
                    $this->nameColumn = $this->myKeyColumn;
664
                }
665
                continue;
666
            }
667
            switch ($keywordInfo) {
668
                case 'INT':
669 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...
670
                    if (is_numeric($what)) {
671
                        $conds[]   = "($keyword = ".$what.')';
672
                        $columns[] = "$keyword";
673
                    }
674
                    break;
675
                case 'TEXT':
676 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...
677
                    if (is_string($what)) {
678
                        $conds[]   = "( $keyword like '".$what."')";
679
                        $columns[] = "$keyword";
680
                    }
681
                    break;
682
                default:
683
                    break;
684
            }
685
        }
686
687
//        $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...
688
689
        $res = $this->getColumnsFromFlexibee($columns, implode(' or ', $conds));
690
691
        foreach ($res as $result) {
692
            $occurences = '';
693
            foreach ($result as $key => $value) {
694
                if (is_array($value)) {
695
                    continue;
696
                }
697
                if (mb_stristr($value, $what)) {
698
                    $occurences .= '('.$key.': '.$value.')';
699
                }
700
            }
701
            $results[$result[$this->myKeyColumn]] = [$this->nameColumn => $result[$this->nameColumn],
702
                'what' => $occurences,];
703
        }
704
705
        return $results;
706
    }
707
708
    /**
709
     * Write Operation Result.
710
     * 
711
     * @param array  $resultData
712
     * @param string $url        URL
713
     */
714
    public function logResult($resultData, $url = null)
715
    {
716
        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...
717
            $this->logger->addStatusMessage($url);
718
        }
719
720
        if (isset($resultData['results'])) {
721
            $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...
722
            if ($resultData['success'] == 'false') {
723
                $status = 'error';
724
            } else {
725
                $status = 'success';
726
            }
727
            foreach ($resultData['results'] as $result) {
728
                if (isset($result['request-id'])) {
729
                    $rid = $result['request-id'];
730
                } else {
731
                    $rid = '';
732
                }
733
                if (isset($result['errors'])) {
734
                    foreach ($result['errors'] as $error) {
735
                        $message = $error['message'];
736
                        if (isset($error['for'])) {
737
                            $message.=' for: '.$error['for'];
738
                        }
739
                        if (isset($error['value'])) {
740
                            $message.=' value:'.$error['value'];
741
                        }
742
                        if (isset($error['code'])) {
743
                            $message.=' code:'.$error['code'];
744
                        }
745
                        $this->logger->addStatusMessage($rid.': '.$message,
746
                            $status);
747
                    }
748
                }
749
            }
750
        }
751
        if (is_object($this->logger)) {
752
            $this->logger->flush(get_class($this));
753
        }
754
    }
755
756
    /**
757
     * Generuje fragment url pro filtrování.
758
     *
759
     * @see https://www.flexibee.eu/api/dokumentace/ref/filters
760
     *
761
     * @param array  $data
762
     * @param string $operator and/or
763
     *
764
     * @return string
765
     */
766
    public static function flexiUrl(array $data, $operator = 'and')
767
    {
768
        $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...
769
        $parts    = [];
770
771
        foreach ($data as $column => $value) {
772
            if (is_numeric($data[$column])) {
773
                $parts[$column] = $column.' = '.$data[$column];
774
            } else {
775
                $parts[$column] = $column." = '".$data[$column]."'";
776
            }
777
        }
778
779
        $flexiUrl = implode(' '.$operator.' ', $parts);
780
781
        return $flexiUrl;
782
    }
783
}