Completed
Push — master ( 4e0ac1...b59c19 )
by Marcus
02:34
created

Helper::addItemToCart()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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