Completed
Push — master ( 60b053...61ce86 )
by Marcus
02:08
created

Helper::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
1
<?php
2
3
/*
4
    HCSF - A multilingual CMS and Shopsystem
5
    Copyright (C) 2014  Marcus Haase - [email protected]
6
7
    This program is free software: you can redistribute it and/or modify
8
    it under the terms of the GNU General Public License as published by
9
    the Free Software Foundation, either version 3 of the License, or
10
    (at your option) any later version.
11
12
    This program is distributed in the hope that it will be useful,
13
    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
    GNU General Public License for more details.
16
17
    You should have received a copy of the GNU General Public License
18
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
namespace HaaseIT\HCSF\Shop;
22
23
24
use Zend\ServiceManager\ServiceManager;
25
26
/**
27
 * Class Helper
28
 * @package HaaseIT\HCSF\Shop
29
 */
30
class Helper
31
{
32
    /**
33
     * @var ServiceManager
34
     */
35
    protected $serviceManager;
36
37
    /**
38
     * @var \HaaseIT\HCSF\HelperConfig
39
     */
40
    protected $config;
41
42
    /**
43
     * @var array
44
     */
45
    protected $shop = [];
46
47
    /**
48
     * @var \HaaseIT\HCSF\Customer\Helper
49
     */
50
    protected $helperCustomer;
51
52
    public function __construct(ServiceManager $serviceManager)
53
    {
54
        $this->serviceManager = $serviceManager;
55
        $this->config = $serviceManager->get('config');
56
        $this->shop = $this->config->getShop();
57
        $this->helperCustomer = $serviceManager->get('helpercustomer');
58
    }
59
60
    /**
61
     * @param \HaaseIT\Toolbox\Textcat $textcats
62
     * @param string $sStatusShort
63
     * @return bool|string
64
     */
65
    public function showOrderStatusText(\HaaseIT\Toolbox\Textcat $textcats, $sStatusShort)
66
    {
67
        $mapping = [
68
            'y' => 'order_status_completed',
69
            'n' => 'order_status_open',
70
            'i' => 'order_status_inwork',
71
            's' => 'order_status_canceled',
72
            'd' => 'order_status_deleted',
73
        ];
74
75
        if (!empty($mapping[$sStatusShort])) {
76
            return $textcats->T($mapping[$sStatusShort]);
77
        }
78
79
        return '';
80
    }
81
82
    /**
83
     * @param array $aOrder
84
     * @return float
85
     */
86
    public function calculateTotalFromDB($aOrder)
87
    {
88
        $fGesamtnetto = $aOrder['o_sumnettoall'];
89
        $fVoll = $aOrder['o_sumvoll'];
90
        $fSteuererm = $aOrder['o_taxerm'];
91
92
        if ($aOrder['o_mindermenge'] > 0) {
93
            $fVoll += $aOrder['o_mindermenge'];
94
            $fGesamtnetto += $aOrder['o_mindermenge'];
95
        }
96
        if ($aOrder['o_shippingcost'] > 0) {
97
            $fVoll += $aOrder['o_shippingcost'];
98
            $fGesamtnetto += $aOrder['o_shippingcost'];
99
        }
100
101
        $fSteuervoll = ($fVoll * $aOrder['o_vatfull'] / 100);
102
103
        return $fGesamtnetto + $fSteuervoll + $fSteuererm;
104
    }
105
106
    /**
107
     * @param array $aSumme
108
     * @param int $iVATfull
109
     * @param int $iVATreduced
110
     * @return array
111
     */
112
    public function addAdditionalCostsToItems($aSumme, $iVATfull, $iVATreduced)
113
    {
114
        $fGesamtnetto = $aSumme['sumvoll'] + $aSumme['sumerm'];
115
        $fSteuervoll = $aSumme['sumvoll'] * $iVATfull / 100;
116
        $fSteuererm = $aSumme['sumerm'] * $iVATreduced / 100;
117
        $fGesamtbrutto = $fGesamtnetto + $fSteuervoll + $fSteuererm;
118
119
        $aOrder = [
120
            'sumvoll' => $aSumme['sumvoll'],
121
            'sumerm' => $aSumme['sumerm'],
122
            'sumnettoall' => $fGesamtnetto,
123
            'taxvoll' => $fSteuervoll,
124
            'taxerm' => $fSteuererm,
125
            'sumbruttoall' => $fGesamtbrutto,
126
        ];
127
128
        $fGesamtnettoitems = $aOrder['sumnettoall'];
129
        $aOrder['fVoll'] = $aOrder['sumvoll'];
130
        $aOrder['fErm'] = $aOrder['sumerm'];
131
        $aOrder['fGesamtnetto'] = $aOrder['sumnettoall'];
132
        $aOrder['fSteuervoll'] = $aOrder['taxvoll'];
133
        $aOrder['fSteuererm'] = $aOrder['taxerm'];
134
        $aOrder['fGesamtbrutto'] = $aOrder['sumbruttoall'];
135
136
        $aOrder['bMindesterreicht'] = true;
137
        $aOrder['fMindergebuehr'] = 0;
138
        $aOrder['iMindergebuehr_id'] = 0;
139
        if ($fGesamtnettoitems < $this->shop['minimumorderamountnet']) {
140
            $aOrder['bMindesterreicht'] = false;
141
            $aOrder['iMindergebuehr_id'] = 0;
142
        } elseif ($fGesamtnettoitems < $this->shop['reducedorderamountnet1']) {
143
            $aOrder['iMindergebuehr_id'] = 1;
144
145
        } elseif ($fGesamtnettoitems < $this->shop['reducedorderamountnet2']) {
146
            $aOrder['iMindergebuehr_id'] = 2;
147
        }
148
149
        if ($aOrder['iMindergebuehr_id'] > 0) {
150
            $aOrder['fVoll'] += $this->shop['reducedorderamountfee'.$aOrder['iMindergebuehr_id']];
151
            $aOrder['fGesamtnetto'] += $this->shop['reducedorderamountfee'.$aOrder['iMindergebuehr_id']];
152
            $aOrder['fSteuervoll'] = $aOrder['fVoll'] * $iVATfull / 100;
153
            $aOrder['fGesamtbrutto'] = $aOrder['fGesamtnetto'] + $aOrder['fSteuervoll'] + $aOrder['fSteuererm'];
154
            $aOrder['fMindergebuehr'] = $this->shop['reducedorderamountfee'.$aOrder['iMindergebuehr_id']];
155
        }
156
157
        $aOrder['fVersandkosten'] = 0;
158
        if (
159
            isset($this->shop['shippingcoststandardrate'])
160
            && $this->shop['shippingcoststandardrate'] != 0
161
            &&
162
            (
163
                (
164
                    !isset($this->shop['mindestbetragversandfrei'])
165
                    || !$this->shop['mindestbetragversandfrei']
166
                )
167
                || $fGesamtnettoitems < $this->shop['mindestbetragversandfrei']
168
            )
169
        ) {
170
            $aOrder['fVersandkostennetto'] = self::getShippingcost();
171
            $aOrder['fVersandkostenvat'] = $aOrder['fVersandkostennetto'] * $iVATfull / 100;
172
            $aOrder['fVersandkostenbrutto'] = $aOrder['fVersandkostennetto'] + $aOrder['fVersandkostenvat'];
173
174
            $aOrder['fSteuervoll'] = ($aOrder['fVoll'] * $iVATfull / 100) + $aOrder['fVersandkostenvat'];
175
            $aOrder['fVoll'] += $aOrder['fVersandkostennetto'];
176
            $aOrder['fGesamtnetto'] += $aOrder['fVersandkostennetto'];
177
            $aOrder['fGesamtbrutto'] = $aOrder['fGesamtnetto'] + $aOrder['fSteuervoll'] + $aOrder['fSteuererm'];
178
        }
179
180
        return $aOrder;
181
    }
182
183
    /**
184
     * @return mixed
185
     */
186
    public function getShippingcost()
0 ignored issues
show
Coding Style introduced by
getShippingcost uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
187
    {
188
        $fShippingcost = $this->shop['shippingcoststandardrate'];
189
190
        $sCountry = $this->helperCustomer->getDefaultCountryByConfig($this->config->getLang());
191
        $postdocheckout = filter_input(INPUT_POST, 'doCheckout');
192
        if (isset($_SESSION['user']['cust_country'])) {
193
            $sCountry = $_SESSION['user']['cust_country'];
194
        } elseif (filter_input(INPUT_POST, 'country') !== null && $postdocheckout === 'yes') {
195
            $sCountry = trim(\HaaseIT\Toolbox\Tools::getFormfield('country'));
196
        } elseif (isset($_SESSION['formsave_addrform']['country'])) {
197
            $sCountry = $_SESSION['formsave_addrform']['country'];
198
        }
199
200
        foreach ($this->shop['shippingcosts'] as $aValue) {
201
            if (isset($aValue['countries'][$sCountry])) {
202
                $fShippingcost = $aValue['cost'];
203
                break;
204
            }
205
        }
206
207
        return $fShippingcost;
208
    }
209
210
    /**
211
     * @param array $aCart
212
     * @return array
213
     */
214
    public function calculateCartItems($aCart)
215
    {
216
        $fErm = 0;
217
        $fVoll = 0;
218
        $fTaxErm = 0;
219
        $fTaxVoll = 0;
220
        foreach ($aCart as $aValue) {
221
            // Hmmmkay, so, if vat is not disabled and there is no vat id or none as vat id set to this item, then
222
            // use the full vat as default. Only use reduced if it is set. Gotta use something as default or item
223
            // will not add up to total price
224
            if ($aValue['vat'] !== 'reduced') {
225
                $fVoll += ($aValue['amount'] * $aValue['price']['netto_use']);
226
                $fTaxVoll += ($aValue['amount'] * $aValue['price']['netto_use'] * ($this->shop['vat']['full'] / 100));
227
                continue;
228
            }
229
230
            $fErm += ($aValue['amount'] * $aValue['price']['netto_use']);
231
            $fTaxErm += ($aValue['amount'] * $aValue['price']['netto_use'] * ($this->shop['vat']['reduced'] / 100));
232
        }
233
234
        return [
235
            'sumvoll' => $fVoll,
236
            'sumerm' => $fErm,
237
            'taxvoll' => $fTaxVoll,
238
            'taxerm' => $fTaxErm
239
        ];
240
    }
241
242
    /**
243
     * @param ServiceManager $serviceManager
244
     */
245
    public function refreshCartItems(ServiceManager $serviceManager) // bei login/logout ändern sich ggf die preise, shoppingcart neu berechnen
0 ignored issues
show
Coding Style introduced by
refreshCartItems uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
246
    {
247
        if (isset($_SESSION['cart']) && is_array($_SESSION['cart'])) {
248
            foreach ($_SESSION['cart'] as $sKey => $aValue) {
249
                $sItemkey = $sKey;
250
                if (!empty($this->shop['custom_order_fields'])) {
251
                    $TMP = explode('|', $sKey);
252
                    $sItemkey = $TMP[0];
253
                    unset($TMP);
254
                }
255
                $aData = $serviceManager->get('oItem')->sortItems('', $sItemkey);
256
                $_SESSION['cart'][$sKey]['price'] = $aData['item'][$sItemkey]['pricedata'];
257
            }
258
        }
259
    }
260
261
    /**
262
     * @param array $aCart
263
     * @param bool $bReadonly
264
     * @param string $sCustomergroup
265
     * @param array $aErr
266
     * @param string $iVATfull
267
     * @param string $iVATreduced
268
     * @return mixed
269
     */
270
    public function buildShoppingCartTable(array $aCart, $bReadonly = false, $sCustomergroup = '', $aErr = [], $iVATfull = '', $iVATreduced = '')
0 ignored issues
show
Coding Style introduced by
buildShoppingCartTable uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
271
    {
272
        if ($iVATfull === '' && $iVATreduced === '') {
273
            $iVATfull = $this->shop['vat']['full'];
274
            $iVATreduced = $this->shop['vat']['reduced'];
275
        }
276
        $aSumme = self::calculateCartItems($aCart);
277
        $aData['shoppingcart'] = [
0 ignored issues
show
Coding Style Comprehensibility introduced by
$aData was never initialized. Although not strictly required by PHP, it is generally a good practice to add $aData = 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...
278
            'readonly' => $bReadonly,
279
            'customergroup' => $sCustomergroup,
280
            'cart' => $aCart,
281
            'rebategroups' => $this->shop['rebate_groups'],
282
            'additionalcoststoitems' => self::addAdditionalCostsToItems($aSumme, $iVATfull, $iVATreduced),
283
            'minimumorderamountnet' => $this->shop['minimumorderamountnet'],
284
            'reducedorderamountnet1' => $this->shop['reducedorderamountnet1'],
285
            'reducedorderamountnet2' => $this->shop['reducedorderamountnet2'],
286
            'reducedorderamountfee1' => $this->shop['reducedorderamountfee1'],
287
            'reducedorderamountfee2' => $this->shop['reducedorderamountfee2'],
288
            'minimumamountforfreeshipping' => $this->shop['minimumamountforfreeshipping'],
289
        ];
290
291
        if (!$bReadonly) {
292
            $aCartpricesums = $aData['shoppingcart']['additionalcoststoitems'];
293
            $_SESSION['cartpricesums'] = $aCartpricesums;
294
        }
295
296
        if (!$bReadonly && $aData['shoppingcart']['additionalcoststoitems']['bMindesterreicht']) {
297
            $aData['customerform'] = $this->helperCustomer->buildCustomerForm($this->config->getLang(), 'shoppingcart', $aErr);
298
        }
299
300
        return $aData;
301
    }
302
303
    /**
304
     * @return array
305
     */
306
    public function getShoppingcartData()
0 ignored issues
show
Coding Style introduced by
getShoppingcartData uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
307
    {
308
        $aCartinfo = [
309
            'numberofitems' => 0,
310
            'cartsums' => [],
311
            'cartsumnetto' => 0,
312
            'cartsumbrutto' => 0,
313
        ];
314
        if (isset($_SESSION['cart']) && (!$this->shop['show_pricesonlytologgedin'] || $this->helperCustomer->getUserData()) && count($_SESSION['cart'])) {
315
            $aCartsums = $this->calculateCartItems($_SESSION['cart']);
316
            $aCartinfo = [
317
                'numberofitems' => count($_SESSION['cart']),
318
                'cartsums' => $aCartsums,
319
                'cartsumnetto' => $aCartsums['sumvoll'] + $aCartsums['sumerm'],
320
                'cartsumbrutto' => $aCartsums['sumvoll'] + $aCartsums['sumerm'] + $aCartsums['taxerm'] + $aCartsums['taxvoll'],
321
            ];
322
            unset($aCartsums);
323
            foreach ($_SESSION['cart'] as $sKey => $aValue) {
324
                $aCartinfo['cartitems'][$sKey] = [
325
                    'cartkey' => $sKey,
326
                    'name' => $aValue['name'],
327
                    'amount' => $aValue['amount'],
328
                    'img' => $aValue['img'],
329
                    'price' => $aValue['price'],
330
                ];
331
            }
332
        }
333
334
        return $aCartinfo;
335
    }
336
337
    /**
338
     * @param Items $oItem
339
     * @param array $aPossibleSuggestions
340
     * @param string $sSetSuggestions
341
     * @param string $sCurrentitem
342
     * @param string|array $mItemindex
343
     * @param array $itemindexpathtree
344
     * @return array
345
     */
346
    public function getItemSuggestions(
347
        Items $oItem,
348
        $aPossibleSuggestions,
349
        $sSetSuggestions,
350
        $sCurrentitem,
351
        $mItemindex,
352
        $itemindexpathtree
353
    )
354
    {
355
        //$aPossibleSuggestions = $aP["items"]["item"]; // put all possible suggestions that are already loaded into this array
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% 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...
356
        unset($aPossibleSuggestions[$sCurrentitem]); // remove the currently shown item from this list, we do not want to show it as a suggestion
357
358
        $suggestions = static::prepareSuggestions($sSetSuggestions, $aPossibleSuggestions, $oItem);
359
360
        $suggestions = static::fillSuggestions($suggestions);
361
362
        foreach ($suggestions as $aSuggestionsKey => $aSuggestionsValue) { // build the paths to the suggested items
363
            if (mb_strpos($aSuggestionsValue['itm_index'], '|') !== false) { // check if the suggestions itemindex contains multiple indexes, if so explode an array
364
                $aSuggestionIndexes = explode('|', $aSuggestionsValue['itm_index']);
365
366
                // iterate through these indexes
367
                foreach ($aSuggestionIndexes as $suggestionindexval) {
368
                    // check if there is an index configured on this page
369
                    if (isset($mItemindex)) {
370
                        // check if it is an array and if the suggestions index is in that array, set path to empty string
371
                        if (is_array($mItemindex) && in_array($suggestionindexval, $mItemindex)) {
372
                            $suggestions[$aSuggestionsKey]['path'] = '';
373
                            // path to suggestion set, continue with next suggestion
374
                            continue 2;
375
                        // if the suggestion index is on this page, set path to empty string
376
                        } elseif ($mItemindex == $suggestionindexval) {
377
                            $suggestions[$aSuggestionsKey]['path'] = '';
378
                            continue 2; // path to suggestion set, continue with next suggestion
379
                        }
380
                    }
381
                    if (isset($itemindexpathtree[$suggestionindexval])) {
382
                        $suggestions[$aSuggestionsKey]['path'] = $itemindexpathtree[$suggestionindexval];
383
                        continue 2;
384
                    }
385
                }
386
            } elseif (isset($itemindexpathtree[$aSuggestionsValue['itm_index']])) {
387
                $suggestions[$aSuggestionsKey]['path'] = $itemindexpathtree[$aSuggestionsValue['itm_index']];
388
            }
389
        }
390
        if ($this->shop['itemdetail_suggestions_shuffle']) {
391
            shuffle($suggestions);
392
        }
393
394
        return $suggestions;
395
    }
396
397
    /**
398
     * @param string $sSetSuggestions - Items defined as Suggestions in Item config
399
     * @param array $aPossibleSuggestions - Items from the same category
400
     * @param Items $oItem
401
     * @return array
402
     */
403
    public function prepareSuggestions($sSetSuggestions, array $aPossibleSuggestions, Items $oItem)
404
    {
405
        // prepare defined suggestions
406
        $sSetSuggestions = trim($sSetSuggestions);
407
        $aDefinedSuggestions = [];
408
        if (!empty($sSetSuggestions)) {
409
            $aDefinedSuggestions = explode('|', $sSetSuggestions);
410
        }
411
412
        // see, which suggestions are not loaded through the current item category yet
413
        $aSuggestionsToLoad = [];
414
        // iterate all defined suggestions and put those not loaded yet into array
415
        foreach ($aDefinedSuggestions as $defisugsval) {
416
            if (!isset($aPossibleSuggestions[$defisugsval])) {
417
                $aSuggestionsToLoad[] = $defisugsval;
418
            }
419
        }
420
421
        // if there are not yet loaded suggestions, load them
422
        if (isset($aSuggestionsToLoad)) {
423
            $aItemsNotInCategory = $oItem->sortItems('', $aSuggestionsToLoad, false);
0 ignored issues
show
Documentation introduced by
$aSuggestionsToLoad is of type array, but the function expects a string.

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...
424
425
            // merge loaded and newly loaded items
426
            if (!empty($aItemsNotInCategory)) {
427
                $aPossibleSuggestions = array_merge($aPossibleSuggestions, $aItemsNotInCategory['item']);
428
            }
429
        }
430
431
        // default = configured suggestions, additional = possible suggestions to fill up to configured maximum
432
        $suggestions = [
433
            'default' => [],
434
            'additional' => [],
435
        ];
436
        // iterate through all possible suggestions
437
        foreach ($aPossibleSuggestions as $posssugskey => $posssugsval) {
438
            if (in_array($posssugskey, $aDefinedSuggestions)) { // if this suggestion is a defined one, put into this array
439
                $suggestions['default'][$posssugskey] = $posssugsval;
440
                continue;
441
            }
442
            // if not, put into this one
443
            $suggestions['additional'][$posssugskey] = $posssugsval;
444
        }
445
446
        // now we see, that the configured suggestions are ordered as configured
447
        $aDefinedSuggestions = array_reverse($aDefinedSuggestions, true);
448
        foreach ($aDefinedSuggestions as $aDefinedSuggestion) {
449
            if (isset($suggestions['default'][$aDefinedSuggestion])) {
450
                $tmp = $suggestions['default'][$aDefinedSuggestion];
451
                unset($suggestions['default'][$aDefinedSuggestion]);
452
                $suggestions['default'] = [$aDefinedSuggestion => $tmp] + $suggestions['default'];
453
            }
454
        }
455
456
        return $suggestions;
457
    }
458
459
    /**
460
     * @param array $suggestions
461
     * @return array
462
     */
463
    public function fillSuggestions($suggestions)
464
    {
465
        $iNumberOfSuggestions = count($suggestions['default']);
466
        if ($iNumberOfSuggestions > $this->shop['itemdetail_suggestions']) { // if there are more suggestions than should be displayed, randomly pick as many as to be shown
467
            $aKeysSuggestions = array_rand($suggestions['default'], $this->shop['itemdetail_suggestions']); // get the array keys that will stay
468
            foreach ($suggestions['default'] as $aSuggestionsKey => $aSuggestionsValue) { // iterate suggestions and remove those that which will not be kept
469
                if (!in_array($aSuggestionsKey, $aKeysSuggestions)) {
470
                    unset($suggestions['default'][$aSuggestionsKey]);
471
                }
472
            }
473
474
            return $suggestions['default'];
475
        }
476
477
        // if less or equal continue here
478
        $numAdditionalSuggs = count($suggestions['additional']);
479
        if (
480
            $numAdditionalSuggs > 0
481
            && $iNumberOfSuggestions < $this->shop['itemdetail_suggestions']
482
        ) { // if there are less suggestions than should be displayed and there are additional available
483
            // how many more are needed?
484
            $addSuggsRequired = $this->shop['itemdetail_suggestions'] - $iNumberOfSuggestions;
485
            // see if there are more available than required, if so, pick as many as needed
486
            if ($numAdditionalSuggs > $addSuggsRequired) {
487
                // since array_rand returns a string and no array if there is only one row picked, we have to do this awkward dance
488
                $keysAddSuggsTMP = array_rand($suggestions['additional'], $addSuggsRequired);
489
                if (is_string($keysAddSuggsTMP) || is_int($keysAddSuggsTMP)) {
490
                    $keysAddSuggsTMP = [$keysAddSuggsTMP];
491
                }
492
                // because array_rand will change numerical (string) values to integer, we have to do this awkward dance
493
                foreach ($keysAddSuggsTMP as $key => $item) {
0 ignored issues
show
Bug introduced by
The expression $keysAddSuggsTMP of type object|double|null|array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
494
                    $keysAddSuggs[] = (string)$item;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$keysAddSuggs was never initialized. Although not strictly required by PHP, it is generally a good practice to add $keysAddSuggs = 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...
495
                }
496
497
                // iterate suggestions and remove those that which will not be kept
498
                foreach ($suggestions['additional'] as $addSuggsKey => $addSuggsVal) {
499
                    if (!in_array((string)$addSuggsKey, $keysAddSuggs, true)) {
0 ignored issues
show
Bug introduced by
The variable $keysAddSuggs 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...
500
                        unset($suggestions['additional'][$addSuggsKey]);
501
                    }
502
                }
503
            }
504
            return array_merge($suggestions['default'], $suggestions['additional']); // merge
505
        }
506
507
        // if the number of default suggestions is not larger than configured and also not smaller, then it equals the
508
        // configured amount, so lets return this then.
509
        return $suggestions['default'];
510
    }
511
512
    /**
513
     * @param ServiceManager $serviceManager
514
     * @param \HaaseIT\HCSF\Page $P
515
     * @param array $aP
516
     * @return mixed
517
     */
518
    public function handleItemPage(ServiceManager $serviceManager, \HaaseIT\HCSF\Page $P, array $aP)
519
    {
520
        $mItemIndex = '';
521
        if (isset($P->cb_pageconfig->itemindex)) {
522
            $mItemIndex = $P->cb_pageconfig->itemindex;
523
        }
524
525
        $oItem = $serviceManager->get('oItem');
526
527
        $aP['items'] = $oItem->sortItems($mItemIndex, '', ($aP['pagetype'] === 'itemoverviewgrpd'));
528
        if ($aP['pagetype'] === 'itemdetail') {
529
530
            $aP['itemindexpathtreeforsuggestions'] = $oItem->getItemPathTree();
531
532
            if (isset($aP['pageconfig']->itemindex)) {
533
                $aP['itemindexpathtreeforsuggestions'][$aP['pageconfig']->itemindex] = '';
534
                if (is_array($aP['pageconfig']->itemindex)) {
535
                    foreach ($aP['pageconfig']->itemindex as $sItemIndexValue) {
536
                        $aP['itemindexpathtreeforsuggestions'][$sItemIndexValue] = '';
537
                    }
538
                }
539
            }
540
541
            $aP = static::seekItem($P, $aP, $oItem);
542
        }
543
544
        return $aP;
545
    }
546
547
    /**
548
     * @param \HaaseIT\HCSF\Page $P
549
     * @param array $aP
550
     * @param Items $oItem
551
     * @return mixed
552
     */
553
    public function seekItem(\HaaseIT\HCSF\Page $P, array $aP, Items $oItem)
554
    {
555
        // Change pagetype to itemoverview, will be changed back to itemdetail once the item is found
556
        // if it is not found, we will show the overview
557
        $aP['pagetype'] = 'itemoverview';
558
        if (count($aP['items']['item'])) {
559
            foreach ($aP['items']['item'] as $sKey => $aValue) {
560
                if ($aValue['itm_no'] != $P->cb_pageconfig->itemno) {
561
                    continue;
562
                }
563
564
                $aP['pagetype'] = 'itemdetail';
565
                $aP['item']['data'] = $aValue;
566
                $aP['item']['key'] = $sKey;
567
568
                if ($aP['items']['totalitems'] > 1) {
569
                    $iPositionInItems = array_search($sKey, $aP['items']['itemkeys']);
570
                    $aP['item']['currentitem'] = $iPositionInItems + 1;
571
572
                    if ($iPositionInItems === 0) {
573
                        $aP['item']['previtem'] = $aP['items']['itemkeys'][$aP['items']['totalitems'] - 1];
574
                    } else {
575
                        $aP['item']['previtem'] = $aP['items']['itemkeys'][$iPositionInItems - 1];
576
                    }
577
578
                    $aP['item']['nextitem'] = $aP['items']['itemkeys'][$iPositionInItems + 1];
579
                    if ($iPositionInItems == $aP['items']['totalitems'] - 1) {
580
                        $aP['item']['nextitem'] = $aP['items']['itemkeys'][0];
581
                    }
582
                } else {
583
                    $aP['item']['currentitem'] = 1;
584
                    $aP['item']['previtem'] = 1;
585
                    $aP['item']['nextitem'] = 1;
586
                }
587
588
                // build item suggestions if needed
589
                if ($this->shop['itemdetail_suggestions'] > 0) {
590
                    $aP['item']['suggestions'] = self::getItemSuggestions(
591
                        $oItem,
592
                        $aP['items']['item'],
593
                        (!empty($aValue['itm_data']['suggestions']) ? $aValue['itm_data']['suggestions'] : ''),
594
                        $sKey,
595
                        (!empty($aP['pageconfig']->itemindex) ? $aP['pageconfig']->itemindex : ''),
596
                        (!empty($aP['itemindexpathtreeforsuggestions']) ? $aP['itemindexpathtreeforsuggestions'] : [])
0 ignored issues
show
Bug introduced by
It seems like !empty($aP['itemindexpat...suggestions'] : array() can also be of type string; however, HaaseIT\HCSF\Shop\Helper::getItemSuggestions() does only seem to accept array, 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...
597
                    );
598
                }
599
                // Wenn der Artikel gefunden wurde können wir das Ausführen der Suche beenden.
600
                break;
601
            }
602
        }
603
604
        return $aP;
605
    }
606
607
    /**
608
     * @param string $itemindex
609
     * @return string
610
     */
611
    public function renderItemStatusIcon($itemindex)
612
    {
613
        if (trim($itemindex) === '') {
614
            return '0';
615
        } elseif (mb_substr($itemindex, 0, 1) === '!') {
616
            return 'X';
617
        }
618
        return 'I';
619
    }
620
621
    // todo: when we use twig 2.x, move this to macro
622
623
    /**
624
     * @param $id
625
     * @return string
626
     */
627
    public function shopadminMakeCheckbox($id)
628
    {
629
        return '<input type="checkbox" name="id[]" value="'.$id.'">';
630
    }
631
}
632