Completed
Push — master ( 42e6bf...4e0ac1 )
by Marcus
02:50
created

Helper::handleItemPage()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 28
rs 8.439
cc 6
eloc 15
nc 8
nop 3
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 HaaseIT\HCSF\HelperConfig;
25
use Zend\ServiceManager\ServiceManager;
26
use HaaseIT\HCSF\Customer\Helper as CHelper;
27
28
class Helper
29
{
30
    public static function showOrderStatusText(\HaaseIT\Toolbox\Textcat $textcats, $sStatusShort)
31
    {
32
        $mapping = [
33
            'y' => 'order_status_completed',
34
            'n' => 'order_status_open',
35
            'i' => 'order_status_inwork',
36
            's' => 'order_status_canceled',
37
            'd' => 'order_status_deleted',
38
        ];
39
40
        if (!empty($mapping[$sStatusShort])) {
41
            return $textcats->T($mapping[$sStatusShort]);
42
        }
43
44
        return '';
45
    }
46
47
    public static function calculateTotalFromDB($aOrder)
48
    {
49
        $fGesamtnetto = $aOrder['o_sumnettoall'];
50
        $fVoll = $aOrder['o_sumvoll'];
51
        $fSteuererm = $aOrder['o_taxerm'];
52
53
        if ($aOrder['o_mindermenge'] > 0) {
54
            $fVoll += $aOrder['o_mindermenge'];
55
            $fGesamtnetto += $aOrder['o_mindermenge'];
56
        }
57
        if ($aOrder['o_shippingcost'] > 0) {
58
            $fVoll += $aOrder['o_shippingcost'];
59
            $fGesamtnetto += $aOrder['o_shippingcost'];
60
        }
61
62
        $fSteuervoll = ($fVoll * $aOrder['o_vatfull'] / 100);
63
64
        return $fGesamtnetto + $fSteuervoll + $fSteuererm;
65
    }
66
67
    public static function addAdditionalCostsToItems($aSumme, $iVATfull, $iVATreduced)
68
    {
69
        $fGesamtnetto = $aSumme['sumvoll'] + $aSumme['sumerm'];
70
        $fSteuervoll = $aSumme['sumvoll'] * $iVATfull / 100;
71
        $fSteuererm = $aSumme['sumerm'] * $iVATreduced / 100;
72
        $fGesamtbrutto = $fGesamtnetto + $fSteuervoll + $fSteuererm;
73
74
        $aOrder = [
75
            'sumvoll' => $aSumme['sumvoll'],
76
            'sumerm' => $aSumme['sumerm'],
77
            'sumnettoall' => $fGesamtnetto,
78
            'taxvoll' => $fSteuervoll,
79
            'taxerm' => $fSteuererm,
80
            'sumbruttoall' => $fGesamtbrutto,
81
        ];
82
83
        $fGesamtnettoitems = $aOrder['sumnettoall'];
84
        $aOrder['fVoll'] = $aOrder['sumvoll'];
85
        $aOrder['fErm'] = $aOrder['sumerm'];
86
        $aOrder['fGesamtnetto'] = $aOrder['sumnettoall'];
87
        $aOrder['fSteuervoll'] = $aOrder['taxvoll'];
88
        $aOrder['fSteuererm'] = $aOrder['taxerm'];
89
        $aOrder['fGesamtbrutto'] = $aOrder['sumbruttoall'];
90
91
        $aOrder['bMindesterreicht'] = true;
92
        $aOrder['fMindergebuehr'] = 0;
93
        $aOrder['iMindergebuehr_id'] = 0;
94
        if ($fGesamtnettoitems < HelperConfig::$shop['minimumorderamountnet']) {
95
            $aOrder['bMindesterreicht'] = false;
96
            $aOrder['iMindergebuehr_id'] = 0;
97
        } elseif ($fGesamtnettoitems < HelperConfig::$shop['reducedorderamountnet1']) {
98
            $aOrder['iMindergebuehr_id'] = 1;
99
100
        } elseif ($fGesamtnettoitems < HelperConfig::$shop['reducedorderamountnet2']) {
101
            $aOrder['iMindergebuehr_id'] = 2;
102
        }
103
104
        if ($aOrder['iMindergebuehr_id'] > 0) {
105
            $aOrder['fVoll'] += HelperConfig::$shop['reducedorderamountfee' . $aOrder['iMindergebuehr_id']];
106
            $aOrder['fGesamtnetto'] += HelperConfig::$shop['reducedorderamountfee' . $aOrder['iMindergebuehr_id']];
107
            $aOrder['fSteuervoll'] = $aOrder['fVoll'] * $iVATfull / 100;
108
            $aOrder['fGesamtbrutto'] = $aOrder['fGesamtnetto'] + $aOrder['fSteuervoll'] + $aOrder['fSteuererm'];
109
            $aOrder['fMindergebuehr'] = HelperConfig::$shop['reducedorderamountfee' . $aOrder['iMindergebuehr_id']];
110
        }
111
112
        $aOrder['fVersandkosten'] = 0;
113
        if (
114
            isset(HelperConfig::$shop['shippingcoststandardrate'])
115
            && HelperConfig::$shop['shippingcoststandardrate'] != 0
116
            &&
117
            (
118
                (
119
                    !isset(HelperConfig::$shop['mindestbetragversandfrei'])
120
                    || !HelperConfig::$shop['mindestbetragversandfrei']
121
                )
122
                || $fGesamtnettoitems < HelperConfig::$shop['mindestbetragversandfrei']
123
            )
124
        ) {
125
            $aOrder['fVersandkostennetto'] = self::getShippingcost();
126
            $aOrder['fVersandkostenvat'] = $aOrder['fVersandkostennetto'] * $iVATfull / 100;
127
            $aOrder['fVersandkostenbrutto'] = $aOrder['fVersandkostennetto'] + $aOrder['fVersandkostenvat'];
128
129
            $aOrder['fSteuervoll'] = ($aOrder['fVoll'] * $iVATfull / 100) + $aOrder['fVersandkostenvat'];
130
            $aOrder['fVoll'] += $aOrder['fVersandkostennetto'];
131
            $aOrder['fGesamtnetto'] += $aOrder['fVersandkostennetto'];
132
            $aOrder['fGesamtbrutto'] = $aOrder['fGesamtnetto'] + $aOrder['fSteuervoll'] + $aOrder['fSteuererm'];
133
        }
134
135
        return $aOrder;
136
    }
137
138
    public static 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...
Coding Style introduced by
getShippingcost uses the super-global variable $_POST 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...
139
    {
140
        $fShippingcost = HelperConfig::$shop['shippingcoststandardrate'];
141
142
        $sCountry = CHelper::getDefaultCountryByConfig(HelperConfig::$lang);
143
        if (isset($_SESSION['user']['cust_country'])) {
144
            $sCountry = $_SESSION['user']['cust_country'];
145
        } elseif (isset($_POST['doCheckout'], $_POST['country']) && $_POST['doCheckout'] === 'yes') {
146
            $sCountry = trim(\HaaseIT\Toolbox\Tools::getFormfield('country'));
147
        } elseif (isset($_SESSION['formsave_addrform']['country'])) {
148
            $sCountry = $_SESSION['formsave_addrform']['country'];
149
        }
150
151
        foreach (HelperConfig::$shop['shippingcosts'] as $aValue) {
152
            if (isset($aValue['countries'][$sCountry])) {
153
                $fShippingcost = $aValue['cost'];
154
                break;
155
            }
156
        }
157
158
        return $fShippingcost;
159
    }
160
161
    public static function calculateCartItems($aCart)
162
    {
163
        $fErm = 0;
164
        $fVoll = 0;
165
        $fTaxErm = 0;
166
        $fTaxVoll = 0;
167
        foreach ($aCart as $aValue) {
168
            // Hmmmkay, so, if vat is not disabled and there is no vat id or none as vat id set to this item, then
169
            // use the full vat as default. Only use reduced if it is set. Gotta use something as default or item
170
            // will not add up to total price
171
            if ($aValue['vat'] != 'reduced') {
172
                $fVoll += ($aValue['amount'] * $aValue['price']['netto_use']);
173
                $fTaxVoll += ($aValue['amount'] * $aValue['price']['netto_use'] * (HelperConfig::$shop['vat']['full'] / 100));
174
                continue;
175
            }
176
177
            $fErm += ($aValue['amount'] * $aValue['price']['netto_use']);
178
            $fTaxErm += ($aValue['amount'] * $aValue['price']['netto_use'] * (HelperConfig::$shop['vat']['reduced'] / 100));
179
        }
180
181
        return [
182
            'sumvoll' => $fVoll,
183
            'sumerm' => $fErm,
184
            'taxvoll' => $fTaxVoll,
185
            'taxerm' => $fTaxErm
186
        ];
187
    }
188
189
    public static 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...
190
    {
191
        if (isset($_SESSION['cart']) && is_array($_SESSION['cart'])) {
192
            foreach ($_SESSION['cart'] as $sKey => $aValue) {
193
                $sItemkey = $sKey;
194
                if (!empty(HelperConfig::$shop['custom_order_fields'])) {
195
                    $TMP = explode('|', $sKey);
196
                    $sItemkey = $TMP[0];
197
                    unset($TMP);
198
                }
199
                $aData = $serviceManager->get('oItem')->sortItems('', $sItemkey);
200
                $_SESSION['cart'][$sKey]['price'] = $aData['item'][$sItemkey]['pricedata'];
201
            }
202
        }
203
    }
204
205
    public static function buildShoppingCartTable($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...
206
    {
207
        if ($iVATfull == '' && $iVATreduced == '') {
208
            $iVATfull = HelperConfig::$shop['vat']['full'];
209
            $iVATreduced = HelperConfig::$shop['vat']['reduced'];
210
        }
211
        $aSumme = self::calculateCartItems($aCart);
212
        $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...
213
            'readonly' => $bReadonly,
214
            'customergroup' => $sCustomergroup,
215
            'cart' => $aCart,
216
            'rebategroups' => HelperConfig::$shop['rebate_groups'],
217
            'additionalcoststoitems' => self::addAdditionalCostsToItems($aSumme, $iVATfull, $iVATreduced),
218
            'minimumorderamountnet' => HelperConfig::$shop['minimumorderamountnet'],
219
            'reducedorderamountnet1' => HelperConfig::$shop['reducedorderamountnet1'],
220
            'reducedorderamountnet2' => HelperConfig::$shop['reducedorderamountnet2'],
221
            'reducedorderamountfee1' => HelperConfig::$shop['reducedorderamountfee1'],
222
            'reducedorderamountfee2' => HelperConfig::$shop['reducedorderamountfee2'],
223
            'minimumamountforfreeshipping' => HelperConfig::$shop['minimumamountforfreeshipping'],
224
        ];
225
226
        if (!$bReadonly) {
227
            $aCartpricesums = $aData['shoppingcart']['additionalcoststoitems'];
228
            $_SESSION['cartpricesums'] = $aCartpricesums;
229
        }
230
231
        if (!$bReadonly && $aData['shoppingcart']['additionalcoststoitems']['bMindesterreicht']) {
232
            $aData['customerform'] = CHelper::buildCustomerForm(HelperConfig::$lang, 'shoppingcart', $aErr);
233
        }
234
235
        return $aData;
236
    }
237
238
    public static 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...
239
    {
240
        $aCartinfo = [
241
            'numberofitems' => 0,
242
            'cartsums' => [],
243
            'cartsumnetto' => 0,
244
            'cartsumbrutto' => 0,
245
        ];
246
        if (isset($_SESSION['cart']) && (!HelperConfig::$shop['show_pricesonlytologgedin'] || CHelper::getUserData()) && count($_SESSION['cart'])) {
247
            $aCartsums = \HaaseIT\HCSF\Shop\Helper::calculateCartItems($_SESSION['cart']);
248
            $aCartinfo = [
249
                'numberofitems' => count($_SESSION['cart']),
250
                'cartsums' => $aCartsums,
251
                'cartsumnetto' => $aCartsums['sumvoll'] + $aCartsums['sumerm'],
252
                'cartsumbrutto' => $aCartsums['sumvoll'] + $aCartsums['sumerm'] + $aCartsums['taxerm'] + $aCartsums['taxvoll'],
253
            ];
254
            unset($aCartsums);
255
            foreach ($_SESSION['cart'] as $sKey => $aValue) {
256
                $aCartinfo['cartitems'][$sKey] = [
257
                    'cartkey' => $sKey,
258
                    'name' => $aValue['name'],
259
                    'amount' => $aValue['amount'],
260
                    'img' => $aValue['img'],
261
                    'price' => $aValue['price'],
262
                ];
263
            }
264
        }
265
266
        return $aCartinfo;
267
    }
268
269
    /**
270
     * @param Items $oItem
271
     * @param array $aPossibleSuggestions
272
     * @param string $sSetSuggestions
273
     * @param string $sCurrentitem
274
     * @param string|array $mItemindex
275
     * @param array $itemindexpathtree
276
     * @return array
277
     */
278
    public static function getItemSuggestions(
279
        Items $oItem,
280
        $aPossibleSuggestions,
281
        $sSetSuggestions,
282
        $sCurrentitem,
283
        $mItemindex,
284
        $itemindexpathtree
285
    )
286
    {
287
        //$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...
288
        unset($aPossibleSuggestions[$sCurrentitem]); // remove the currently shown item from this list, we do not want to show it as a suggestion
289
290
        $suggestions = static::prepareSuggestions($sSetSuggestions, $aPossibleSuggestions, $oItem);
291
292
        $suggestions = static::fillSuggestions($suggestions);
293
294
        foreach ($suggestions as $aSuggestionsKey => $aSuggestionsValue) { // build the paths to the suggested items
295
            if (mb_strpos($aSuggestionsValue['itm_index'], '|') !== false) { // check if the suggestions itemindex contains multiple indexes, if so explode an array
296
                $aSuggestionIndexes = explode('|', $aSuggestionsValue['itm_index']);
297
298
                // iterate through these indexes
299
                foreach ($aSuggestionIndexes as $suggestionindexval) {
300
                    // check if there is an index configured on this page
301
                    if (isset($mItemindex)) {
302
                        // check if it is an array and if the suggestions index is in that array, set path to empty string
303
                        if (is_array($mItemindex) && in_array($suggestionindexval, $mItemindex)) {
304
                            $suggestions[$aSuggestionsKey]['path'] = '';
305
                            // path to suggestion set, continue with next suggestion
306
                            continue 2;
307
                        // if the suggestion index is on this page, set path to empty string
308
                        } elseif ($mItemindex == $suggestionindexval) {
309
                            $suggestions[$aSuggestionsKey]['path'] = '';
310
                            continue 2; // path to suggestion set, continue with next suggestion
311
                        }
312
                    }
313
                    if (isset($itemindexpathtree[$suggestionindexval])) {
314
                        $suggestions[$aSuggestionsKey]['path'] = $itemindexpathtree[$suggestionindexval];
315
                        continue 2;
316
                    }
317
                }
318
            } elseif (isset($itemindexpathtree[$aSuggestionsValue['itm_index']])) {
319
                $suggestions[$aSuggestionsKey]['path'] = $itemindexpathtree[$aSuggestionsValue['itm_index']];
320
            }
321
        }
322
        if (HelperConfig::$shop['itemdetail_suggestions_shuffle']) {
323
            shuffle($suggestions);
324
        }
325
326
        return $suggestions;
327
    }
328
329
    /**
330
     * @param string $sSetSuggestions - Items defined as Suggestions in Item config
331
     * @param array $aPossibleSuggestions - Items from the same category
332
     * @param Items $oItem
333
     * @return array
334
     */
335
    public static function prepareSuggestions($sSetSuggestions, array $aPossibleSuggestions, Items $oItem)
336
    {
337
        // prepare defined suggestions
338
        $sSetSuggestions = trim($sSetSuggestions);
339
        $aDefinedSuggestions = [];
340
        if (!empty($sSetSuggestions)) {
341
            $aDefinedSuggestions = explode('|', $sSetSuggestions);
342
        }
343
344
        // see, which suggestions are not loaded through the current item category yet
345
        $aSuggestionsToLoad = [];
346
        // iterate all defined suggestions and put those not loaded yet into array
347
        foreach ($aDefinedSuggestions as $defisugsval) {
348
            if (!isset($aPossibleSuggestions[$defisugsval])) {
349
                $aSuggestionsToLoad[] = $defisugsval;
350
            }
351
        }
352
353
        // if there are not yet loaded suggestions, load them
354
        if (isset($aSuggestionsToLoad)) {
355
            $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...
356
357
            // merge loaded and newly loaded items
358
            if (!empty($aItemsNotInCategory)) {
359
                $aPossibleSuggestions = array_merge($aPossibleSuggestions, $aItemsNotInCategory['item']);
360
            }
361
        }
362
363
        // default = configured suggestions, additional = possible suggestions to fill up to configured maximum
364
        $suggestions = [
365
            'default' => [],
366
            'additional' => [],
367
        ];
368
        // iterate through all possible suggestions
369
        foreach ($aPossibleSuggestions as $posssugskey => $posssugsval) {
370
            if (in_array($posssugskey, $aDefinedSuggestions)) { // if this suggestion is a defined one, put into this array
371
                $suggestions['default'][$posssugskey] = $posssugsval;
372
                continue;
373
            }
374
            // if not, put into this one
375
            $suggestions['additional'][$posssugskey] = $posssugsval;
376
        }
377
378
        // now we see, that the configured suggestions are ordered as configured
379
        $aDefinedSuggestions = array_reverse($aDefinedSuggestions, true);
380
        foreach ($aDefinedSuggestions as $aDefinedSuggestion) {
381
            if (isset($suggestions['default'][$aDefinedSuggestion])) {
382
                $tmp = $suggestions['default'][$aDefinedSuggestion];
383
                unset($suggestions['default'][$aDefinedSuggestion]);
384
                $suggestions['default'] = [$aDefinedSuggestion => $tmp] + $suggestions['default'];
385
            }
386
        }
387
388
        return $suggestions;
389
    }
390
391
    /**
392
     * @param array $suggestions
393
     * @return array
394
     */
395
    public static function fillSuggestions($suggestions)
396
    {
397
        $iNumberOfSuggestions = count($suggestions['default']);
398
        if ($iNumberOfSuggestions > HelperConfig::$shop['itemdetail_suggestions']) { // if there are more suggestions than should be displayed, randomly pick as many as to be shown
399
            $aKeysSuggestions = array_rand($suggestions['default'], HelperConfig::$shop['itemdetail_suggestions']); // get the array keys that will stay
400
            foreach ($suggestions['default'] as $aSuggestionsKey => $aSuggestionsValue) { // iterate suggestions and remove those that which will not be kept
401
                if (!in_array($aSuggestionsKey, $aKeysSuggestions)) {
402
                    unset($suggestions['default'][$aSuggestionsKey]);
403
                }
404
            }
405
406
            return $suggestions['default'];
407
        }
408
409
        // if less or equal continue here
410
        $numAdditionalSuggs = count($suggestions['additional']);
411
        if (
412
            $numAdditionalSuggs > 0
413
            && $iNumberOfSuggestions < HelperConfig::$shop['itemdetail_suggestions']
414
        ) { // if there are less suggestions than should be displayed and there are additional available
415
            // how many more are needed?
416
            $addSuggsRequired = HelperConfig::$shop['itemdetail_suggestions'] - $iNumberOfSuggestions;
417
            // see if there are more available than required, if so, pick as many as needed
418
            if ($numAdditionalSuggs > $addSuggsRequired) {
419
                // since array_rand returns a string and no array if there is only one row picked, we have to do this awkward dance
420
                $keysAddSuggsTMP = array_rand($suggestions['additional'], $addSuggsRequired);
421
                if (is_string($keysAddSuggsTMP) || is_int($keysAddSuggsTMP)) {
422
                    $keysAddSuggsTMP = [$keysAddSuggsTMP];
423
                }
424
                // because array_rand will change numerical (string) values to integer, we have to do this awkward dance
425
                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...
426
                    $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...
427
                }
428
429
                // iterate suggestions and remove those that which will not be kept
430
                foreach ($suggestions['additional'] as $addSuggsKey => $addSuggsVal) {
431
                    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...
432
                        unset($suggestions['additional'][$addSuggsKey]);
433
                    }
434
                }
435
            }
436
            return array_merge($suggestions['default'], $suggestions['additional']); // merge
437
        }
438
439
        // if the number of default suggestions is not larger than configured and also not smaller, then it equals the
440
        // configured amount, so lets return this then.
441
        return $suggestions['default'];
442
    }
443
444
    public static function handleItemPage(ServiceManager $serviceManager, \HaaseIT\HCSF\Page $P, $aP)
445
    {
446
        $mItemIndex = '';
447
        if (isset($P->cb_pageconfig->itemindex)) {
448
            $mItemIndex = $P->cb_pageconfig->itemindex;
449
        }
450
451
        $oItem = $serviceManager->get('oItem');
452
453
        $aP['items'] = $oItem->sortItems($mItemIndex, '', ($aP['pagetype'] === 'itemoverviewgrpd'));
454
        if ($aP['pagetype'] === 'itemdetail') {
455
456
            $aP['itemindexpathtreeforsuggestions'] = $oItem->getItemPathTree();
457
458
            if (isset($aP['pageconfig']->itemindex)) {
459
                $aP['itemindexpathtreeforsuggestions'][$aP['pageconfig']->itemindex] = '';
460
                if (is_array($aP['pageconfig']->itemindex)) {
461
                    foreach ($aP['pageconfig']->itemindex as $sItemIndexValue) {
462
                        $aP['itemindexpathtreeforsuggestions'][$sItemIndexValue] = '';
463
                    }
464
                }
465
            }
466
467
            $aP = static::seekItem($P, $aP, $oItem);
468
        }
469
470
        return $aP;
471
    }
472
473
    public static function seekItem(\HaaseIT\HCSF\Page $P, $aP, Items $oItem)
474
    {
475
        // Change pagetype to itemoverview, will be changed back to itemdetail once the item is found
476
        // if it is not found, we will show the overview
477
        $aP['pagetype'] = 'itemoverview';
478
        if (count($aP['items']['item'])) {
479
            foreach ($aP['items']['item'] as $sKey => $aValue) {
480
                if ($aValue['itm_no'] != $P->cb_pageconfig->itemno) {
481
                    continue;
482
                }
483
484
                $aP['pagetype'] = 'itemdetail';
485
                $aP['item']['data'] = $aValue;
486
                $aP['item']['key'] = $sKey;
487
488
                if ($aP['items']['totalitems'] > 1) {
489
                    $iPositionInItems = array_search($sKey, $aP['items']['itemkeys']);
490
                    $aP['item']['currentitem'] = $iPositionInItems + 1;
491
492
                    if ($iPositionInItems === 0) {
493
                        $aP['item']['previtem'] = $aP['items']['itemkeys'][$aP['items']['totalitems'] - 1];
494
                    } else {
495
                        $aP['item']['previtem'] = $aP['items']['itemkeys'][$iPositionInItems - 1];
496
                    }
497
498
                    $aP['item']['nextitem'] = $aP['items']['itemkeys'][$iPositionInItems + 1];
499
                    if ($iPositionInItems == $aP['items']['totalitems'] - 1) {
500
                        $aP['item']['nextitem'] = $aP['items']['itemkeys'][0];
501
                    }
502
                } else {
503
                    $aP['item']['currentitem'] = 1;
504
                    $aP['item']['previtem'] = 1;
505
                    $aP['item']['nextitem'] = 1;
506
                }
507
508
                // build item suggestions if needed
509
                if (HelperConfig::$shop['itemdetail_suggestions'] > 0) {
510
                    $aP['item']['suggestions'] = self::getItemSuggestions(
511
                        $oItem,
512
                        $aP['items']['item'],
513
                        (!empty($aValue['itm_data']['suggestions']) ? $aValue['itm_data']['suggestions'] : ''),
514
                        $sKey,
515
                        (!empty($aP['pageconfig']->itemindex) ? $aP['pageconfig']->itemindex : ''),
516
                        (!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...
517
                    );
518
                }
519
                // Wenn der Artikel gefunden wurde können wir das Ausführen der Suche beenden.
520
                break;
521
            }
522
        }
523
524
        return $aP;
525
    }
526
527
    public static function renderItemStatusIcon($itemindex)
528
    {
529
        if (trim($itemindex) === '') {
530
            return '0';
531
        } elseif (mb_substr($itemindex, 0, 1) === '!') {
532
            return 'X';
533
        }
534
        return 'I';
535
    }
536
537
    // todo: when we use twig 2.x, move this to macro
538
    public static function shopadminMakeCheckbox($id)
539
    {
540
        return '<input type="checkbox" name="id[]" value="'.$id.'">';
541
    }
542
}