Completed
Push — master ( ce178a...31732a )
by Marcus
02:32
created

Updatecart::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\Controller\Shop;
22
23
use HaaseIT\HCSF\HelperConfig;
24
25
/**
26
 * Class Updatecart
27
 * @package HaaseIT\HCSF\Controller\Shop
28
 */
29
class Updatecart extends Base
30
{
31
    /**
32
     *
33
     */
34
    public function preparePage()
0 ignored issues
show
Coding Style introduced by
preparePage uses the super-global variable $_SERVER 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
preparePage uses the super-global variable $_REQUEST 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
preparePage 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
preparePage 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...
35
    {
36
        $this->P = new \HaaseIT\HCSF\CorePage($this->serviceManager);
37
        $this->P->cb_pagetype = 'content';
38
39
        if (
40
            (
41
                HelperConfig::$shop['show_pricesonlytologgedin']
42
                && !\HaaseIT\HCSF\Customer\Helper::getUserData()
43
            )
44
            || !isset($_SERVER['HTTP_REFERER'])
45
        ) {
46
            $this->P->oPayload->cl_html = $this->serviceManager->get('textcats')->T('denied_default');
47
        } else {
48
            $iAmount = '';
49
            if (isset($_REQUEST['amount'])) {
50
                $iAmount = $_REQUEST['amount'];
51
            }
52
53
            if (empty($_REQUEST['itemno']) || !is_numeric($iAmount)) {
54
                $this->replyToCartUpdate('noitemnooramount');
55
            } else {
56
                $iAmount = floor($iAmount);
57
58
                // Check if this item exists
59
                $aData = $this->serviceManager->get('oItem')->sortItems('', $_REQUEST['itemno']);
60
                if (!isset($aData)) {
61
                    $this->replyToCartUpdate('itemnotfound');
62
                } else {
63
                    // are there additional items to this item, if so, check if they are valid, too.
64
                    if (!empty($_POST['additionalitems'])) {
65
                        $additionalitems = filter_input(INPUT_POST, 'additionalitems', FILTER_SANITIZE_SPECIAL_CHARS);
66
67
                        if (strpos($additionalitems, '~') !== false) {
68
                            $additionalitems = explode('~', $additionalitems);
69
                        } else {
70
                            $additionalitems = [$additionalitems];
71
                        }
72
73
                        $additionaldata = $this->serviceManager->get('oItem')->sortItems('', $additionalitems);
74
75
                        if (count($additionalitems) != count($additionaldata['item'])) {
76
                            $this->replyToCartUpdate('itemnotfound');
77
                        }
78
                    }
79
80
                    // build the key for this item for the shoppingcart
81
                    $sItemno = $aData['item'][$_REQUEST['itemno']]['itm_no'];
82
                    $sCartKey = $sItemno;
83
84
                    if (isset(HelperConfig::$shop['custom_order_fields'])) {
85
                        foreach (HelperConfig::$shop['custom_order_fields'] as $sValue) {
86
                            if (isset($aData['item'][$sItemno]['itm_data'][$sValue])) {
87
                                $aOptions = [];
88
                                $TMP = explode('|', $aData['item'][$sItemno]['itm_data'][$sValue]);
89
                                foreach ($TMP as $sTMPValue) {
90
                                    if (trim($sTMPValue) != '') {
91
                                        $aOptions[] = $sTMPValue;
92
                                    }
93
                                }
94
                                unset($sTMP);
95
96
                                if (isset($_REQUEST[$sValue]) && in_array($_REQUEST[$sValue], $aOptions)) {
97
                                    $sCartKey .= '|' . $sValue . ':' . $_REQUEST[$sValue];
98
                                } else {
99
                                    $this->replyToCartUpdate('requiredfieldmissing');
100
                                }
101
                            }
102
                        }
103
                    }
104
                    // if this Items is not in cart and amount is 0, no need to do anything, return to referer
105
                    if ($iAmount == 0 && !isset($_SESSION['cart'][$sCartKey])) {
106
                        $this->replyToCartUpdate('noactiontaken');
107
                    }
108
                    $aItem = [
109
                        'amount' => $iAmount,
110
                        'price' => $this->serviceManager->get('oItem')->calcPrice($aData['item'][$sItemno]),
111
                        'rg' => $aData['item'][$sItemno]['itm_rg'],
112
                        'vat' => $aData['item'][$sItemno]['itm_vatid'],
113
                        'name' => $aData['item'][$sItemno]['itm_name'],
114
                        'img' => $aData['item'][$sItemno]['itm_img'],
115
                    ];
116
                    if (!empty($_POST['action']) && $_POST['action'] === 'add') {
117
                        $this->addItemToCart($sCartKey, $aItem);
118
119
                        if (!empty($additionalitems)) {
120
                            foreach ($additionalitems as $additionalitem) {
121
                                $this->addItemToCart(
122
                                    $additionalitem,
123
                                    [
124
                                        'amount' => $iAmount,
125
                                        'price' => $this->serviceManager->get('oItem')->calcPrice($additionaldata['item'][$additionalitem]),
0 ignored issues
show
Bug introduced by
The variable $additionaldata 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...
126
                                        'rg' => $additionaldata['item'][$additionalitem]['itm_rg'],
127
                                        'vat' => $additionaldata['item'][$additionalitem]['itm_vatid'],
128
                                        'name' => $additionaldata['item'][$additionalitem]['itm_name'],
129
                                        'img' => $additionaldata['item'][$additionalitem]['itm_img'],
130
                                    ]
131
                                );
132
                            }
133
                        }
134
                    } else {
135
                        if (isset($_SESSION['cart'][$sCartKey])) { // if this item is already in cart, update amount
136
                            if ($iAmount == 0) { // new amount == 0 -> remove from cart
137
                                unset($_SESSION['cart'][$sCartKey]);
138
                                if (count($_SESSION['cart']) == 0) { // once the last cart item is unset, we no longer need cartpricesums
139
                                    unset($_SESSION['cartpricesums']);
140
                                }
141
                                $this->replyToCartUpdate('removed', ['cartkey' => $sCartKey]);
142
                            } else { // update amount
143
                                $_SESSION['cart'][$sCartKey]['amount'] = $iAmount;
144
                                $this->replyToCartUpdate('updated', ['cartkey' => $sCartKey, 'amount' => $iAmount]);
145
                            }
146
                        } else { // if this item is not in the cart yet, add it
147
                            $_SESSION['cart'][$sCartKey] = $aItem;
148
                        }
149
                    }
150
                    $this->replyToCartUpdate('added', ['cartkey' => $sCartKey, 'amount' => $iAmount]);
151
                }
152
            }
153
            die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method preparePage() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
154
        }
155
    }
156
157
    /**
158
     * @param string $sReply
159
     * @param array $aMore
160
     */
161
    private function replyToCartUpdate($sReply, $aMore = []) {
0 ignored issues
show
Coding Style introduced by
replyToCartUpdate uses the super-global variable $_REQUEST 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
replyToCartUpdate 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
replyToCartUpdate uses the super-global variable $_SERVER 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...
162
        if (isset($_REQUEST['ajax'])) {
163
            $aAR = [
164
                'cart' => $_SESSION['cart'],
165
                'reply' => $sReply,
166
                'cartsums' => \HaaseIT\HCSF\Shop\Helper::calculateCartItems($_SESSION['cart']),
167
                'currency' => HelperConfig::$shop['waehrungssymbol'],
168
                'numberformat_decimals' => HelperConfig::$core['numberformat_decimals'],
169
                'numberformat_decimal_point' => HelperConfig::$core['numberformat_decimal_point'],
170
                'numberformat_thousands_seperator' => HelperConfig::$core['numberformat_thousands_seperator'],
171
            ];
172
            if (count($aMore)) {
173
                $aAR = array_merge($aAR, $aMore);
174
            }
175
            echo $this->serviceManager->get('twig')->render('shop/update-cart.twig', $aAR);
176
        } else {
177
            $aMSG['msg'] =  $sReply;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$aMSG was never initialized. Although not strictly required by PHP, it is generally a good practice to add $aMSG = 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...
178
            if (count($aMore)) {
179
                $aMSG = array_merge($aMSG, $aMore);
180
            }
181
            header('Location: '.\HaaseIT\Toolbox\Tools::makeLinkHRefWithAddedGetVars($_SERVER['HTTP_REFERER'], $aMSG, true, false));
182
        }
183
        die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method replyToCartUpdate() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
184
    }
185
186
    protected 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...
187
    {
188
        if (isset($_SESSION['cart'][$cartkey])) { // if this item is already in cart, add to amount
189
            $_SESSION['cart'][$cartkey]['amount'] += $item['amount'];
190
        } else {
191
            $_SESSION['cart'][$cartkey] = $item;
192
        }
193
194
        return true;
195
    }
196
}