Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Shoppingcart 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 Shoppingcart, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 29 | class Shoppingcart extends Base |
||
| 30 | { |
||
| 31 | /** |
||
| 32 | * @var \HaaseIT\Toolbox\Textcat |
||
| 33 | */ |
||
| 34 | private $textcats; |
||
| 35 | |||
| 36 | /** |
||
| 37 | * Shoppingcart constructor. |
||
| 38 | * @param \Zend\ServiceManager\ServiceManager $serviceManager |
||
| 39 | */ |
||
| 40 | public function __construct(\Zend\ServiceManager\ServiceManager $serviceManager) |
||
| 41 | { |
||
| 42 | parent::__construct($serviceManager); |
||
| 43 | $this->textcats = $this->serviceManager->get('textcats'); |
||
| 44 | } |
||
| 45 | |||
| 46 | /** |
||
| 47 | * |
||
| 48 | */ |
||
| 49 | public function preparePage() |
||
|
|
|||
| 50 | { |
||
| 51 | $this->P = new \HaaseIT\HCSF\CorePage($this->serviceManager); |
||
| 52 | $this->P->cb_pagetype = 'contentnosubnav'; |
||
| 53 | |||
| 54 | if (HelperConfig::$shop['show_pricesonlytologgedin'] && !CHelper::getUserData()) { |
||
| 55 | $this->P->oPayload->cl_html = $this->textcats->T('denied_notloggedin'); |
||
| 56 | } else { |
||
| 57 | $this->P->cb_customcontenttemplate = 'shop/shoppingcart'; |
||
| 58 | |||
| 59 | // Check if there is a message to display above the shoppingcart |
||
| 60 | $this->P->oPayload->cl_html = $this->getNotification(); |
||
| 61 | |||
| 62 | // Display the shoppingcart |
||
| 63 | if (isset($_SESSION['cart']) && count($_SESSION['cart']) >= 1) { |
||
| 64 | $aErr = []; |
||
| 65 | if (filter_input(INPUT_POST, 'doCheckout') === 'yes') { |
||
| 66 | $aErr = $this->validateCheckout($aErr); |
||
| 67 | if (count($aErr) === 0) { |
||
| 68 | $this->doCheckout(); |
||
| 69 | } |
||
| 70 | } |
||
| 71 | |||
| 72 | $aShoppingcart = SHelper::buildShoppingCartTable($_SESSION['cart'], false, '', $aErr); |
||
| 73 | |||
| 74 | $this->P->cb_customdata = $aShoppingcart; |
||
| 75 | } else { |
||
| 76 | $this->P->oPayload->cl_html .= $this->textcats->T('shoppingcart_empty'); |
||
| 77 | } |
||
| 78 | } |
||
| 79 | } |
||
| 80 | |||
| 81 | /** |
||
| 82 | * @param array $aErr |
||
| 83 | * @return array |
||
| 84 | */ |
||
| 85 | private function validateCheckout($aErr = []) |
||
| 86 | { |
||
| 87 | $aErr = CHelper::validateCustomerForm(HelperConfig::$lang, $aErr, true); |
||
| 88 | View Code Duplication | if (!CHelper::getUserData() && filter_input(INPUT_POST, 'tos') !== 'y') { |
|
| 89 | $aErr['tos'] = true; |
||
| 90 | } |
||
| 91 | View Code Duplication | if (!CHelper::getUserData() && filter_input(INPUT_POST, 'cancellationdisclaimer') !== 'y') { |
|
| 92 | $aErr['cancellationdisclaimer'] = true; |
||
| 93 | } |
||
| 94 | $postpaymentmethod = filter_input(INPUT_POST, 'paymentmethod'); |
||
| 95 | if ( |
||
| 96 | $postpaymentmethod === null |
||
| 97 | || in_array($postpaymentmethod, HelperConfig::$shop['paymentmethods'], true) === false |
||
| 98 | ) { |
||
| 99 | $aErr['paymentmethod'] = true; |
||
| 100 | } |
||
| 101 | |||
| 102 | return $aErr; |
||
| 103 | } |
||
| 104 | |||
| 105 | /** |
||
| 106 | * @param $aV |
||
| 107 | * @return array |
||
| 108 | */ |
||
| 109 | private function getItemImage($aV) |
||
| 110 | { |
||
| 111 | // base64 encode img and prepare for db |
||
| 112 | // image/png image/jpeg image/gif |
||
| 113 | // data:{mimetype};base64,XXXX |
||
|
1 ignored issue
–
show
|
|||
| 114 | |||
| 115 | $aImagesToSend = []; |
||
| 116 | $base64Img = false; |
||
| 117 | $binImg = false; |
||
| 118 | |||
| 119 | if (HelperConfig::$shop['email_orderconfirmation_embed_itemimages_method'] === 'glide') { |
||
| 120 | $sPathToImage = '/'.HelperConfig::$core['directory_images'].'/'.HelperConfig::$shop['directory_images_items'].'/'; |
||
| 121 | $sImageroot = PATH_BASEDIR . HelperConfig::$core['directory_glide_master']; |
||
| 122 | |||
| 123 | if ( |
||
| 124 | is_file($sImageroot.substr($sPathToImage.$aV['img'], strlen(HelperConfig::$core['directory_images']) + 1)) |
||
| 125 | && $aImgInfo = getimagesize($sImageroot.substr($sPathToImage.$aV['img'], strlen(HelperConfig::$core['directory_images']) + 1)) |
||
| 126 | ) { |
||
| 127 | $glideserver = \League\Glide\ServerFactory::create([ |
||
| 128 | 'source' => $sImageroot, |
||
| 129 | 'cache' => PATH_GLIDECACHE, |
||
| 130 | 'max_image_size' => HelperConfig::$core['glide_max_imagesize'], |
||
| 131 | ]); |
||
| 132 | $glideserver->setBaseUrl('/' . HelperConfig::$core['directory_images'] . '/'); |
||
| 133 | $base64Img = $glideserver->getImageAsBase64($sPathToImage.$aV['img'], HelperConfig::$shop['email_orderconfirmation_embed_itemimages_glideparams']); |
||
| 134 | $TMP = explode(',', $base64Img); |
||
| 135 | $binImg = base64_decode($TMP[1]); |
||
| 136 | unset($TMP); |
||
| 137 | } |
||
| 138 | } else { |
||
| 139 | $sPathToImage = |
||
| 140 | PATH_DOCROOT.HelperConfig::$core['directory_images'].'/' |
||
| 141 | .HelperConfig::$shop['directory_images_items'].'/' |
||
| 142 | .HelperConfig::$shop['directory_images_items_email'].'/'; |
||
| 143 | if ($aImgInfo = getimagesize($sPathToImage.$aV['img'])) { |
||
| 144 | $binImg = file_get_contents($sPathToImage.$aV['img']); |
||
| 145 | $base64Img = 'data:' . $aImgInfo['mime'] . ';base64,'; |
||
| 146 | $base64Img .= base64_encode($binImg); |
||
| 147 | } |
||
| 148 | } |
||
| 149 | if (HelperConfig::$shop['email_orderconfirmation_embed_itemimages']) { |
||
| 150 | $aImagesToSend['binimg'] = $binImg; |
||
| 151 | } |
||
| 152 | if ($base64Img) { |
||
| 153 | $aImagesToSend['base64img'] = $base64Img; |
||
| 154 | } |
||
| 155 | return $aImagesToSend; |
||
| 156 | } |
||
| 157 | |||
| 158 | /** |
||
| 159 | * @return array |
||
| 160 | */ |
||
| 161 | private function prepareDataOrder() |
||
| 162 | { |
||
| 163 | $cartpricesums = $_SESSION['cartpricesums']; |
||
| 164 | return [ |
||
| 165 | 'o_custno' => filter_var(trim(Tools::getFormfield('custno')), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 166 | 'o_email' => filter_var(trim(Tools::getFormfield('email')), FILTER_SANITIZE_EMAIL), |
||
| 167 | 'o_corpname' => filter_var(trim(Tools::getFormfield('corpname')), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 168 | 'o_name' => filter_var(trim(Tools::getFormfield('name')), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 169 | 'o_street' => filter_var(trim(Tools::getFormfield('street')), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 170 | 'o_zip' => filter_var(trim(Tools::getFormfield('zip')), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 171 | 'o_town' => filter_var(trim(Tools::getFormfield('town')), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 172 | 'o_phone' => filter_var(trim(Tools::getFormfield('phone')), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 173 | 'o_cellphone' => filter_var(trim(Tools::getFormfield('cellphone')), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 174 | 'o_fax' => filter_var(trim(Tools::getFormfield('fax')), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 175 | 'o_country' => filter_var(trim(Tools::getFormfield('country')), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 176 | 'o_group' => trim(CHelper::getUserData('cust_group')), |
||
| 177 | 'o_remarks' => filter_var(trim(Tools::getFormfield('remarks')), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 178 | 'o_tos' => (filter_input(INPUT_POST, 'tos') === 'y' || CHelper::getUserData()) ? 'y' : 'n', |
||
| 179 | 'o_cancellationdisclaimer' => (filter_input(INPUT_POST, 'cancellationdisclaimer') === 'y' || CHelper::getUserData()) ? 'y' : 'n', |
||
| 180 | 'o_paymentmethod' => filter_var(trim(Tools::getFormfield('paymentmethod')), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 181 | 'o_sumvoll' => $cartpricesums['sumvoll'], |
||
| 182 | 'o_sumerm' => $cartpricesums['sumerm'], |
||
| 183 | 'o_sumnettoall' => $cartpricesums['sumnettoall'], |
||
| 184 | 'o_taxvoll' => $cartpricesums['taxvoll'], |
||
| 185 | 'o_taxerm' => $cartpricesums['taxerm'], |
||
| 186 | 'o_sumbruttoall' => $cartpricesums['sumbruttoall'], |
||
| 187 | 'o_mindermenge' => isset($cartpricesums['mindergebuehr']) ? $cartpricesums['mindergebuehr'] : '', |
||
| 188 | 'o_shippingcost' => SHelper::getShippingcost(), |
||
| 189 | 'o_orderdate' => date('Y-m-d'), |
||
| 190 | 'o_ordertimestamp' => time(), |
||
| 191 | 'o_authed' => CHelper::getUserData() ? 'y' : 'n', |
||
| 192 | 'o_sessiondata' => serialize($_SESSION), |
||
| 193 | 'o_postdata' => serialize($_POST), |
||
| 194 | 'o_remote_address' => filter_input(INPUT_SERVER, 'REMOTE_ADDR', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 195 | 'o_ordercompleted' => 'n', |
||
| 196 | 'o_paymentcompleted' => 'n', |
||
| 197 | 'o_srv_hostname' => filter_input(INPUT_SERVER, 'SERVER_NAME', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW), |
||
| 198 | 'o_vatfull' => HelperConfig::$shop['vat']['full'], |
||
| 199 | 'o_vatreduced' => HelperConfig::$shop['vat']['reduced'], |
||
| 200 | ]; |
||
| 201 | } |
||
| 202 | |||
| 203 | /** |
||
| 204 | * @param int $orderid |
||
| 205 | * @param string $cartkey |
||
| 206 | * @param array $values |
||
| 207 | * @param string $image |
||
| 208 | * @return array |
||
| 209 | */ |
||
| 210 | private function buildOrderItemRow($orderid, $cartkey, array $values, $image) |
||
| 211 | { |
||
| 212 | return [ |
||
| 213 | 'oi_o_id' => $orderid, |
||
| 214 | 'oi_cartkey' => $cartkey, |
||
| 215 | 'oi_amount' => $values['amount'], |
||
| 216 | 'oi_price_netto_list' => $values['price']['netto_list'], |
||
| 217 | 'oi_price_netto_use' => $values['price']['netto_use'], |
||
| 218 | 'oi_price_brutto_use' => $values['price']['brutto_use'], |
||
| 219 | 'oi_price_netto_sale' => isset($values['price']['netto_sale']) ? $values['price']['netto_sale'] : '', |
||
| 220 | 'oi_price_netto_rebated' => isset($values['price']['netto_rebated']) ? $values['price']['netto_rebated'] : '', |
||
| 221 | 'oi_vat' => HelperConfig::$shop['vat'][$values['vat']], |
||
| 222 | 'oi_rg' => $values['rg'], |
||
| 223 | 'oi_rg_rebate' => isset( |
||
| 224 | HelperConfig::$shop['rebate_groups'][$values['rg']][trim(CHelper::getUserData('cust_group'))] |
||
| 225 | ) |
||
| 226 | ? HelperConfig::$shop['rebate_groups'][$values['rg']][trim(CHelper::getUserData('cust_group'))] |
||
| 227 | : '', |
||
| 228 | 'oi_itemname' => $values['name'], |
||
| 229 | 'oi_img' => $image, |
||
| 230 | ]; |
||
| 231 | } |
||
| 232 | |||
| 233 | private function doCheckout() |
||
| 234 | { |
||
| 235 | /** @var \Doctrine\DBAL\Connection $dbal */ |
||
| 236 | $dbal = $this->serviceManager->get('dbal'); |
||
| 237 | |||
| 238 | try { |
||
| 239 | $dbal->beginTransaction(); |
||
| 240 | |||
| 241 | $aDataOrder = $this->prepareDataOrder(); |
||
| 242 | |||
| 243 | $iInsertID = \HaaseIT\HCSF\Helper::autoInsert($dbal, 'orders', $aDataOrder); |
||
| 244 | |||
| 245 | $aImagesToSend = []; |
||
| 246 | foreach ($_SESSION['cart'] as $sK => $aV) { |
||
| 247 | $aImagesToSend[$aV['img']] = $this->getItemImage($aV); |
||
| 248 | |||
| 249 | \HaaseIT\HCSF\Helper::autoInsert( |
||
| 250 | $dbal, |
||
| 251 | 'orders_items', |
||
| 252 | $this->buildOrderItemRow($iInsertID, $sK, $aV, $aImagesToSend[$aV['img']]['base64img']) |
||
| 253 | ); |
||
| 254 | } |
||
| 255 | $dbal->commit(); |
||
| 256 | } catch (\Exception $e) { |
||
| 257 | // If something raised an exception in our transaction block of statements, |
||
| 258 | // roll back any work performed in the transaction |
||
| 259 | print '<p>Unable to complete transaction!</p>'; |
||
| 260 | error_log($e); |
||
| 261 | $dbal->rollBack(); |
||
| 262 | } |
||
| 263 | $sMailbody_us = $this->buildOrderMailBody(false, $iInsertID); |
||
| 264 | $sMailbody_they = $this->buildOrderMailBody(true, $iInsertID); |
||
| 265 | |||
| 266 | // write to file |
||
| 267 | $this->writeCheckoutToFile($sMailbody_us); |
||
| 268 | |||
| 269 | // Send Mails |
||
| 270 | $this->sendCheckoutMails($iInsertID, $sMailbody_us, $sMailbody_they, $aImagesToSend); |
||
| 271 | |||
| 272 | unset($_SESSION['cart'], $_SESSION['cartpricesums'], $_SESSION['sondercart']); |
||
| 273 | |||
| 274 | $postpaymentmethod = filter_input(INPUT_POST, 'paymentmethod'); |
||
| 275 | if ( |
||
| 276 | $postpaymentmethod !== null |
||
| 277 | && isset(HelperConfig::$shop['paypal_interactive']) |
||
| 278 | && $postpaymentmethod === 'paypal' |
||
| 279 | && in_array('paypal', HelperConfig::$shop['paymentmethods'], true) !== false |
||
| 280 | && HelperConfig::$shop['paypal_interactive'] |
||
| 281 | ) { |
||
| 282 | $redirectto = '/_misc/paypal.html?id=' . $iInsertID; |
||
| 283 | } elseif ( |
||
| 284 | $postpaymentmethod !== null |
||
| 285 | && $postpaymentmethod === 'sofortueberweisung' |
||
| 286 | && in_array('sofortueberweisung', HelperConfig::$shop['paymentmethods'], true) !== false |
||
| 287 | ) { |
||
| 288 | $redirectto = '/_misc/sofortueberweisung.html?id=' . $iInsertID; |
||
| 289 | } else { |
||
| 290 | $redirectto = '/_misc/checkedout.html?id=' . $iInsertID; |
||
| 291 | } |
||
| 292 | \HaaseIT\HCSF\Helper::redirectToPage($redirectto); |
||
| 293 | } |
||
| 294 | |||
| 295 | /** |
||
| 296 | * @param int $iInsertID |
||
| 297 | * @param string $sMailbody_us |
||
| 298 | * @param string $sMailbody_they |
||
| 299 | * @param array $aImagesToSend |
||
| 300 | */ |
||
| 301 | private function sendCheckoutMails($iInsertID, $sMailbody_us, $sMailbody_they, $aImagesToSend) |
||
| 332 | |||
| 333 | /** |
||
| 334 | * @param string $sMailbody_us |
||
| 335 | */ |
||
| 336 | private function writeCheckoutToFile($sMailbody_us) |
||
| 343 | |||
| 344 | /** |
||
| 345 | * @param string $field |
||
| 346 | * @return string |
||
| 347 | */ |
||
| 348 | private function getPostValue($field) |
||
| 353 | |||
| 354 | /** |
||
| 355 | * @param bool $bCust |
||
| 356 | * @param int $iId |
||
| 357 | * @return mixed |
||
| 358 | */ |
||
| 359 | private function buildOrderMailBody($bCust = true, $iId) |
||
| 411 | |||
| 412 | /** |
||
| 413 | * @return string |
||
| 414 | */ |
||
| 415 | private function getNotification() |
||
| 452 | } |
||
| 453 |
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: