Items   B
last analyzed

Complexity

Total Complexity 49

Size/Duplication

Total Lines 270
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 49
lcom 1
cbo 4
dl 0
loc 270
rs 8.48
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B getItemPathTree() 0 30 8
B queryItem() 0 29 7
B queryItemWhereClause() 0 35 8
B sortItems() 0 47 10
A getGroupdata() 0 16 1
C calcPrice() 0 53 13
A addVat() 0 14 1

How to fix   Complexity   

Complex Class

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

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

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

1
<?php
2
3
/*
4
    HCSF - A multilingual CMS and Shopsystem
5
    Copyright (C) 2014  Marcus Haase - [email protected]
6
7
    This program is free software: you can redistribute it and/or modify
8
    it under the terms of the GNU General Public License as published by
9
    the Free Software Foundation, either version 3 of the License, or
10
    (at your option) any later version.
11
12
    This program is distributed in the hope that it will be useful,
13
    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
    GNU General Public License for more details.
16
17
    You should have received a copy of the GNU General Public License
18
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
namespace HaaseIT\HCSF\Shop;
22
23
24
use Zend\ServiceManager\ServiceManager;
25
26
/**
27
 * Class Items
28
 * @package HaaseIT\HCSF\Shop
29
 */
30
class Items
31
{
32
    /**
33
     * @var \PDO
34
     */
35
    private $db;
36
37
    /**
38
     * @var \HaaseIT\HCSF\HelperConfig
39
     */
40
    protected $config;
41
42
    /**
43
     * @var \HaaseIT\HCSF\Customer\Helper
44
     */
45
    protected $helperCustomer;
46
47
    /**
48
     * Items constructor.
49
     * @param ServiceManager $serviceManager
50
     */
51
    public function __construct(ServiceManager $serviceManager)
52
    {
53
        $this->db = $serviceManager->get('db');
54
        $this->config = $serviceManager->get('config');
55
        $this->helperCustomer = $serviceManager->get('helpercustomer');
56
    }
57
58
    public function getItemPathTree()
59
    {
60
        $itemindexpathtree = [];
61
        $aItemoverviewpages = [];
62
        $sql = "SELECT * FROM content_base WHERE cb_pagetype = 'itemoverview' OR cb_pagetype = 'itemoverviewgrpd'";
63
        $oQuery = $this->db->query($sql);
64
        while ($aRow = $oQuery->fetch()) {
65
            $aItemoverviewpages[] = [
66
                'path' => $aRow['cb_key'],
67
                'pageconfig' => json_decode($aRow['cb_pageconfig']),
68
            ];
69
        }
70
        foreach ($aItemoverviewpages as $aValue) {
71
            if (isset($aValue['pageconfig']->itemindex)) {
72
                if (is_array($aValue['pageconfig']->itemindex)) {
73
                    foreach ($aValue['pageconfig']->itemindex as $sIndexValue) {
74
                        if (!isset($itemindexpathtree[$sIndexValue])) {
75
                            $itemindexpathtree[$sIndexValue] = mb_substr($aValue['path'], 0, mb_strlen($aValue['path']) - 10).'item/';
76
                        }
77
                    }
78
                } else {
79
                    if (!isset($itemindexpathtree[$aValue['pageconfig']->itemindex])) {
80
                        $itemindexpathtree[$aValue['pageconfig']->itemindex] = mb_substr($aValue['path'], 0, mb_strlen($aValue['path']) - 10).'item/';
81
                    }
82
                }
83
            }
84
        }
85
86
        return $itemindexpathtree;
87
    }
88
89
    public function queryItem($mItemIndex = '', $mItemno = '', $sOrderby = '')
90
    {
91
        $sql = 'SELECT '.DB_ITEMFIELDS.' FROM item_base';
92
        $sql .= ' LEFT OUTER JOIN item_lang ON item_base.itm_id = item_lang.itml_pid AND itml_lang = :lang';
93
        $sql .= $this->queryItemWhereClause($mItemIndex, $mItemno);
94
        $sql .= ' ORDER BY '.(($sOrderby === '') ? 'itm_order, itm_no' : $sOrderby).' '.$this->config->getShop('items_orderdirection_default');
95
96
        $hResult = $this->db->prepare($sql);
97
        $hResult->bindValue(':lang', $this->config->getLang(), \PDO::PARAM_STR);
98
        $getsearchtext = filter_input(INPUT_GET, 'searchtext', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
99
        if (!empty($mItemno)) {
100
            if (!is_array($mItemno)) {
101
                $hResult->bindValue(':itemno', $mItemno, \PDO::PARAM_STR);
102
            }
103
        } elseif (!empty($getsearchtext) && strlen(trim($getsearchtext)) > 2) {
104
            if (filter_input(INPUT_GET, 'artnoexact') !== null) {
105
                $hResult->bindValue(':searchtext', $getsearchtext, \PDO::PARAM_STR);
106
            } else {
107
                $hResult->bindValue(':searchtextwild1', '%'.$getsearchtext.'%', \PDO::PARAM_STR);
108
                $hResult->bindValue(':searchtextwild2', '%'.$getsearchtext.'%', \PDO::PARAM_STR);
109
                $hResult->bindValue(':searchtextwild3', '%'.$getsearchtext.'%', \PDO::PARAM_STR);
110
                $hResult->bindValue(':searchtextwild4', '%'.$getsearchtext.'%', \PDO::PARAM_STR);
111
                $hResult->bindValue(':searchtextwild5', '%'.$getsearchtext.'%', \PDO::PARAM_STR);
112
            }
113
        }
114
        $hResult->execute();
115
116
        return $hResult;
117
    }
118
119
    /**
120
     * @param string|array $mItemIndex
121
     * @param string|array $mItemno
122
     * @return string
123
     */
124
    public function queryItemWhereClause($mItemIndex = '', $mItemno = '')
125
    {
126
        $sql = ' WHERE ';
127
        $getsearchtext = filter_input(INPUT_GET, 'searchtext', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
128
        if (!empty($mItemno)) {
129
            if (is_array($mItemno)) {
130
                $sItemno = "'".\implode("','", \filter_var_array($mItemno, FILTER_SANITIZE_SPECIAL_CHARS))."'";
131
                $sql .= 'item_base.itm_no IN ('.$sItemno.')';
132
            } else {
133
                $sql .= 'item_base.itm_no = :itemno';
134
            }
135
        } elseif (!empty($getsearchtext) && strlen(trim($getsearchtext)) > 2) {
136
            if (filter_input(INPUT_GET, 'artnoexact') !== null) {
137
                $sql .= 'item_base.itm_no = :searchtext';
138
            } else {
139
                $sql .= '(item_base.itm_no LIKE :searchtextwild1 OR itm_name LIKE :searchtextwild2';
140
                $sql .= ' OR itml_name_override LIKE :searchtextwild3 OR itml_text1 LIKE :searchtextwild4';
141
                $sql .= ' OR itml_text2 LIKE :searchtextwild5)';
142
            }
143
        } else {
144
            if (is_array($mItemIndex)) {
145
                $sql .= '(';
146
                foreach ($mItemIndex as $sAIndex) {
147
                    $sql .= "itm_index LIKE '%".filter_var($sAIndex, FILTER_SANITIZE_SPECIAL_CHARS)."%' OR ";
148
                }
149
                $sql = \HaaseIT\Toolbox\Tools::cutStringend($sql, 4);
150
                $sql .= ')';
151
            } else {
152
                $sql .= "itm_index LIKE '%".filter_var($mItemIndex, FILTER_SANITIZE_SPECIAL_CHARS)."%'";
153
            }
154
        }
155
        $sql .= ' AND itm_index NOT LIKE \'%!%\' AND itm_index NOT LIKE \'%AL%\'';
156
157
        return $sql;
158
    }
159
160
    /**
161
     * @param string $mItemIndex
162
     * @param string $mItemno
163
     * @param bool $bEnableItemGroups
164
     * @return bool|array
165
     */
166
    public function sortItems($mItemIndex = '', $mItemno = '', $bEnableItemGroups = false)
167
    {
168
        if ($mItemno !== '') {
169
            if (\is_array($mItemno)) {
170
                $TMP = [];
171
                foreach ($mItemno as $sKey => $sValue) {
172
                    $TMP[$sKey] = filter_var(\trim($sValue), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
173
                }
174
                $mItemno = $TMP;
175
                unset($TMP);
176
            } else {
177
                $mItemno = filter_var(\trim($mItemno), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
178
            }
179
        }
180
181
        $hResult = $this->queryItem($mItemIndex, $mItemno);
182
183
        while ($aRow = $hResult->fetch()) {
184
            if (isset($aRow['itm_data'])) {
185
                $aRow['itm_data'] = \json_decode($aRow['itm_data'], true);
186
            }
187
            $aRow['pricedata'] = $this->calcPrice($aRow);
188
189
            if (!$bEnableItemGroups || \trim($aRow['itm_group']) == 0) {
190
                $aAssembly['item'][$aRow['itm_no']] = $aRow;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$aAssembly was never initialized. Although not strictly required by PHP, it is generally a good practice to add $aAssembly = 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...
191
            } else {
192
                if (isset($aAssembly['groups']['ITEMGROUP-' .$aRow['itm_group']])) {
193
                    $aAssembly['groups']['ITEMGROUP-' .$aRow['itm_group']][$aRow['itm_no']] = $aRow;
194
                } else {
195
                    $aAssembly['item']['ITEMGROUP-' .$aRow['itm_group']]['group'] = 'ITEMGROUP-' .$aRow['itm_group'];
0 ignored issues
show
Bug introduced by
The variable $aAssembly 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...
196
                    $aAssembly['groups']['ITEMGROUP-' .$aRow['itm_group']]['ITEMGROUP-DATA'] = $this->getGroupdata($aRow['itm_group']);
197
                    $aAssembly['groups']['ITEMGROUP-' .$aRow['itm_group']][$aRow['itm_no']] = $aRow;
198
                }
199
            }
200
        }
201
202
        if (isset($aAssembly)) {
203
            $aAssembly['totalitems'] = \count($aAssembly['item']);
204
            $aAssembly['itemkeys'] = \array_keys($aAssembly['item']);
205
            $aAssembly['firstitem'] = $aAssembly['itemkeys'][0];
206
            $aAssembly['lastitem'] = $aAssembly['itemkeys'][$aAssembly['totalitems'] - 1];
207
208
            return $aAssembly;
209
        }
210
211
        return false;
212
    }
213
214
    public function getGroupdata($sGroup)
215
    {
216
        $sql = 'SELECT '.DB_ITEMGROUPFIELDS.' FROM itemgroups_base'
217
           .' LEFT OUTER JOIN itemgroups_text ON itemgroups_base.itmg_id = itemgroups_text.itmgt_pid'
218
           .' AND itmgt_lang = :lang'
219
           .' WHERE itmg_id = :group';
220
221
        $hResult = $this->db->prepare($sql);
222
        $hResult->bindValue(':lang', $this->config->getLang(), \PDO::PARAM_STR);
223
        $hResult->bindValue(':group', $sGroup, \PDO::PARAM_INT);
224
        $hResult->execute();
225
226
        $aRow = $hResult->fetch();
227
        $aRow['type'] = 'itemgroupdata';
228
        return $aRow;
229
    }
230
231
    public function calcPrice($aData)
232
    {
233
        $aPrice = [];
234
        if ($aData['itm_vatid'] !== 'reduced') {
235
            $aData['itm_vatid'] = 'full';
236
        }
237
238
        if(is_numeric($aData['itm_price']) && (float) $aData['itm_price'] > 0) {
239
            $aPrice['netto_list'] = $aData['itm_price'];
240
            $aPrice['brutto_list'] = $this->addVat($aPrice['netto_list'], $this->config->getShop('vat')[$aData['itm_vatid']]);
241
            if (
242
                isset($aData['itm_data']['sale']['start'], $aData['itm_data']['sale']['end'], $aData['itm_data']['sale']['price'])
243
            ) {
244
                $iToday = date('Ymd');
245
                if ($iToday >= $aData['itm_data']['sale']['start'] && $iToday <= $aData['itm_data']['sale']['end']) {
246
                    $aPrice['netto_sale'] = $aData['itm_data']['sale']['price'];
247
                    $aPrice['brutto_sale'] = $this->addVat($aPrice['netto_sale'], $this->config->getShop('vat')[$aData['itm_vatid']]);
248
                }
249
            }
250
            if (
251
                $aData['itm_rg'] !== ''
252
                && isset($this->config->getShop('rebate_groups')[$aData['itm_rg']][$this->helperCustomer->getUserData('cust_group')])
253
            ) {
254
                $aPrice['netto_rebated'] =
255
                    bcmul(
256
                        $aData['itm_price'],
257
                        bcdiv(
258
                            bcsub(
259
                                '100',
260
                                (string)$this->config->getShop('rebate_groups')[$aData['itm_rg']][$this->helperCustomer->getUserData('cust_group')]
261
                            ),
262
                            '100'
263
                        )
264
                    );
265
                $aPrice['brutto_rebated'] = $this->addVat($aPrice['netto_rebated'], $this->config->getShop('vat')[$aData['itm_vatid']]);
266
            }
267
        } else {
268
            return false;
269
        }
270
271
        $aPrice['netto_use'] = $aPrice['netto_list'];
272
273
        if (isset($aPrice['netto_rebated']) && $aPrice['netto_rebated'] < $aPrice['netto_use']) {
274
            $aPrice['netto_use'] = $aPrice['netto_rebated'];
275
        }
276
        if (isset($aPrice['netto_sale']) && $aPrice['netto_sale'] < $aPrice['netto_use']) {
277
            $aPrice['netto_use'] = $aPrice['netto_sale'];
278
        }
279
280
        $aPrice['brutto_use'] = $this->addVat($aPrice['netto_use'], $this->config->getShop('vat')[$aData['itm_vatid']]);
281
282
        return $aPrice;
283
    }
284
285
    private function addVat($price, $vat)
286
    {
287
        return
288
            bcadd(
289
                bcdiv(
290
                    bcmul(
291
                        $price,
292
                        (string)$vat
293
                    ),
294
                    '100'
295
                ),
296
                $price
297
            );
298
    }
299
}
300