sunnysideup /
silverstripe-ecommerce
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * This class is the form for editing the Order Addresses. |
||
| 5 | * It is also used to link the order to a member. |
||
| 6 | * |
||
| 7 | * @authors: Nicolaas [at] Sunny Side Up .co.nz |
||
| 8 | * @package: ecommerce |
||
| 9 | * @sub-package: forms |
||
| 10 | * @inspiration: Silverstripe Ltd, Jeremy |
||
| 11 | **/ |
||
| 12 | class OrderFormAddress extends Form |
||
| 13 | { |
||
| 14 | /** |
||
| 15 | * @var bool |
||
| 16 | */ |
||
| 17 | protected $debug = false; |
||
| 18 | |||
| 19 | /** |
||
| 20 | * @var array |
||
| 21 | */ |
||
| 22 | protected $debugArray = array(); |
||
| 23 | |||
| 24 | /** |
||
| 25 | * the member attached to the order |
||
| 26 | * this is not always the same as the loggedInMember. |
||
| 27 | * |
||
| 28 | * @var object (Member) |
||
| 29 | */ |
||
| 30 | protected $orderMember = null; |
||
| 31 | |||
| 32 | /** |
||
| 33 | * the logged in member, if any |
||
| 34 | * this is not always the same as the orderMember. |
||
| 35 | * |
||
| 36 | * @var object (Member) |
||
| 37 | */ |
||
| 38 | protected $loggedInMember = null; |
||
| 39 | |||
| 40 | /** |
||
| 41 | * ID of the member that has just been created. |
||
| 42 | * |
||
| 43 | * @var int |
||
| 44 | */ |
||
| 45 | protected $newlyCreatedMemberID = 0; |
||
| 46 | |||
| 47 | /** |
||
| 48 | * ID of the member that has just been created. |
||
| 49 | * |
||
| 50 | * @var Order |
||
| 51 | */ |
||
| 52 | protected $order = null; |
||
| 53 | |||
| 54 | /** |
||
| 55 | * @param Controller |
||
| 56 | * @param string |
||
| 57 | */ |
||
| 58 | public function __construct(Controller $controller, $name) |
||
| 59 | { |
||
| 60 | |||
| 61 | //set basics |
||
| 62 | $requiredFields = array(); |
||
| 63 | |||
| 64 | //requirements |
||
| 65 | Requirements::javascript('ecommerce/javascript/EcomOrderFormAddress.js'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE |
||
| 66 | if (EcommerceConfig::get('OrderAddress', 'use_separate_shipping_address')) { |
||
| 67 | Requirements::javascript('ecommerce/javascript/EcomOrderFormShipping.js'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE |
||
| 68 | } |
||
| 69 | |||
| 70 | // ________________ 1) Order + Member + Address fields |
||
| 71 | |||
| 72 | |||
| 73 | // define field lists ... |
||
| 74 | $addressFieldsMember = FieldList::create(); |
||
| 75 | $addressFieldsBilling = FieldList::create(); |
||
| 76 | $addressFieldsShipping = null; |
||
| 77 | $useShippingAddressField = null; |
||
| 78 | $shippingAddressFirst = EcommerceConfig::get('OrderFormAddress', 'shipping_address_first'); |
||
| 79 | |||
| 80 | $addressFieldsMember->push( |
||
| 81 | HeaderField::create( |
||
| 82 | 'AddressFieldsMemberHeading', |
||
| 83 | _t('OrderFormAddress.Address_Fields_Member_Heading', 'Your Personal Details'), |
||
| 84 | 3 |
||
| 85 | ) |
||
| 86 | ); |
||
| 87 | //find member |
||
| 88 | $this->order = ShoppingCart::current_order(); |
||
| 89 | $this->orderMember = $this->order->CreateOrReturnExistingMember(false); |
||
| 90 | $this->loggedInMember = Member::currentUser(); |
||
| 91 | |||
| 92 | //strange security situation... |
||
| 93 | if ($this->orderMember->exists() && $this->loggedInMember) { |
||
| 94 | if ($this->orderMember->ID != $this->loggedInMember->ID) { |
||
| 95 | if (!$this->loggedInMember->IsShopAdmin()) { |
||
| 96 | $this->loggedInMember->logOut(); |
||
| 97 | } |
||
| 98 | } |
||
| 99 | } |
||
| 100 | |||
| 101 | //member fields |
||
| 102 | if ($this->orderMember) { |
||
| 103 | $memberFields = $this->orderMember->getEcommerceFields(); |
||
| 104 | $requiredFields = array_merge($requiredFields, $this->orderMember->getEcommerceRequiredFields()); |
||
| 105 | $addressFieldsMember->merge($memberFields); |
||
| 106 | } |
||
| 107 | |||
| 108 | //billing address field |
||
| 109 | $billingAddress = $this->order->CreateOrReturnExistingAddress('BillingAddress'); |
||
| 110 | $billingAddressFields = $billingAddress->getFields($this->orderMember); |
||
| 111 | $addressFieldsBilling->merge($billingAddressFields); |
||
| 112 | |||
| 113 | $requiredFields = array_merge($requiredFields, $billingAddress->getRequiredFields()); |
||
| 114 | |||
| 115 | //HACK: move phone to member fields .. |
||
| 116 | if ($addressFieldsMember) { |
||
| 117 | if ($addressFieldsBilling) { |
||
| 118 | if ($phoneField = $addressFieldsBilling->dataFieldByName('Phone')) { |
||
| 119 | $addressFieldsBilling->removeByName('Phone'); |
||
| 120 | $addressFieldsMember->insertAfter('Email', $phoneField); |
||
| 121 | } |
||
| 122 | } |
||
| 123 | } |
||
| 124 | |||
| 125 | |||
| 126 | //shipping address field |
||
| 127 | |||
| 128 | if (EcommerceConfig::get('OrderAddress', 'use_separate_shipping_address')) { |
||
| 129 | //add the important CHECKBOX |
||
| 130 | $useShippingAddressField = FieldList::create( |
||
| 131 | HeaderField::create( |
||
| 132 | 'HasShippingAddressHeader', |
||
| 133 | _t('OrderFormAddress.HAS_SHIPPING_ADDRESS_HEADER', 'Delivery Option'), |
||
| 134 | 3 |
||
| 135 | ) |
||
| 136 | ); |
||
| 137 | $useShippingAddress = $this->order ? $this->order->UseShippingAddress : 0; |
||
|
0 ignored issues
–
show
|
|||
| 138 | if ($shippingAddressFirst) { |
||
| 139 | $useShippingAddressField->push( |
||
| 140 | CheckboxField::create( |
||
| 141 | 'UseDifferentShippingAddress', |
||
| 142 | _t('OrderForm.USE_DIFFERENT_SHIPPING_ADDRESS', 'I need to enter a separate billing address'), |
||
| 143 | $useShippingAddress |
||
| 144 | ) |
||
| 145 | ); |
||
| 146 | $useShippingAddressField->push( |
||
| 147 | HiddenField::create('UseShippingAddress', 'UseShippingAddress', $useShippingAddress) |
||
| 148 | ); |
||
| 149 | } else { |
||
| 150 | $useShippingAddressField->push( |
||
| 151 | CheckboxField::create( |
||
| 152 | 'UseShippingAddress', |
||
| 153 | _t('OrderForm.USESHIPPINGADDRESS', 'Use separate shipping address'), |
||
| 154 | $useShippingAddress |
||
| 155 | ) |
||
| 156 | ); |
||
| 157 | } |
||
| 158 | |||
| 159 | $addressFieldsShipping = FieldList::create(); |
||
| 160 | |||
| 161 | //$addressFieldsShipping->merge($useShippingAddressField); |
||
| 162 | //now we can add the shipping fields |
||
| 163 | $shippingAddress = $this->order->CreateOrReturnExistingAddress('ShippingAddress'); |
||
| 164 | $shippingAddressFields = $shippingAddress->getFields($this->orderMember); |
||
| 165 | $requiredFields = array_merge($requiredFields, $shippingAddress->getRequiredFields()); |
||
| 166 | $addressFieldsShipping->merge($shippingAddressFields); |
||
| 167 | } |
||
| 168 | |||
| 169 | //create holder |
||
| 170 | $allLeftFields = CompositeField::create(); |
||
| 171 | $allLeftFields->addExtraClass('leftOrder'); |
||
| 172 | |||
| 173 | //member fields holder |
||
| 174 | $leftFieldsMember = CompositeField::create($addressFieldsMember); |
||
| 175 | $leftFieldsMember->addExtraClass('leftOrderMember'); |
||
| 176 | |||
| 177 | //creating shipping fields holder |
||
| 178 | $leftFieldsShipping = CompositeField::create($addressFieldsShipping); |
||
| 179 | $leftFieldsShipping->addExtraClass('leftOrderShipping'); |
||
| 180 | |||
| 181 | //creating billing fields holder |
||
| 182 | $leftFieldsBilling = CompositeField::create($addressFieldsBilling); |
||
| 183 | $leftFieldsBilling->addExtraClass('leftOrderBilling'); |
||
| 184 | |||
| 185 | //adding member fields ... |
||
| 186 | $allLeftFields->push($leftFieldsMember); |
||
| 187 | if ($useShippingAddressField) { |
||
| 188 | $leftFieldsShippingOptions = CompositeField::create($useShippingAddressField); |
||
| 189 | $leftFieldsShippingOptions->addExtraClass('leftOrderShippingOptions'); |
||
| 190 | $allLeftFields->push($leftFieldsShippingOptions); |
||
| 191 | } |
||
| 192 | if ($shippingAddressFirst) { |
||
| 193 | if ($addressFieldsShipping) { |
||
| 194 | $allLeftFields->push($leftFieldsShipping); |
||
| 195 | } |
||
| 196 | $allLeftFields->push($leftFieldsBilling); |
||
| 197 | } else { |
||
| 198 | $allLeftFields->push($leftFieldsBilling); |
||
| 199 | if ($addressFieldsShipping) { |
||
| 200 | $allLeftFields->push($leftFieldsShipping); |
||
| 201 | } |
||
| 202 | } |
||
| 203 | |||
| 204 | // ________________ 2) Log in / vs Create Account fields - RIGHT-HAND-SIDE fields |
||
| 205 | |||
| 206 | $rightFields = CompositeField::create(); |
||
| 207 | $rightFields->addExtraClass('rightOrder'); |
||
| 208 | //to do: simplify |
||
| 209 | if (EcommerceConfig::get('EcommerceRole', 'allow_customers_to_setup_accounts')) { |
||
| 210 | if ($this->orderDoesNotHaveFullyOperationalMember()) { |
||
| 211 | //general header |
||
| 212 | if (!$this->loggedInMember) { |
||
| 213 | $rightFields->push( |
||
| 214 | //TODO: check EXACT link!!! |
||
| 215 | new LiteralField('MemberInfo', '<p class="message good">'._t('OrderForm.MEMBERINFO', 'If you already have an account then please').' <a href="Security/login/?BackURL=/'.urlencode(implode('/', $controller->getURLParams())).'">'._t('OrderForm.LOGIN', 'log in').'</a>.</p>') |
||
| 216 | ); |
||
| 217 | } |
||
| 218 | } else { |
||
| 219 | if ($this->loggedInMember) { |
||
| 220 | $rightFields->push( |
||
| 221 | new LiteralField( |
||
| 222 | 'LoginNote', |
||
| 223 | '<p class="message good">'._t('Account.LOGGEDIN', 'You are logged in as '). |
||
| 224 | Convert::raw2xml($this->loggedInMember->FirstName).' '. |
||
| 225 | Convert::raw2xml($this->loggedInMember->Surname). |
||
| 226 | ' ('.Convert::raw2xml($this->loggedInMember->Email).').'. |
||
| 227 | ' <a href="/Security/logout/">'. |
||
| 228 | _t('Account.LOGOUTNOW', 'Log out?'). |
||
| 229 | '</a>'. |
||
| 230 | '</p>' |
||
| 231 | ) |
||
| 232 | ); |
||
| 233 | } |
||
| 234 | } |
||
| 235 | if ($this->orderMember->exists()) { |
||
| 236 | if ($this->loggedInMember) { |
||
| 237 | if ($this->loggedInMember->ID != $this->orderMember->ID) { |
||
| 238 | $rightFields->push( |
||
| 239 | new LiteralField( |
||
| 240 | 'OrderAddedTo', |
||
| 241 | '<p class="message good">'. |
||
| 242 | _t('Account.ORDERADDEDTO', 'Order will be added to '). |
||
| 243 | Convert::raw2xml($this->orderMember->FirstName).' '. |
||
| 244 | Convert::raw2xml($this->orderMember->Surname).' ('. |
||
| 245 | Convert::raw2xml($this->orderMember->Email). |
||
| 246 | ').</p>' |
||
| 247 | ) |
||
| 248 | ); |
||
| 249 | } |
||
| 250 | } |
||
| 251 | } |
||
| 252 | } |
||
| 253 | |||
| 254 | // ________________ 5) Put all the fields in one FieldList |
||
| 255 | |||
| 256 | $fields = FieldList::create($rightFields, $allLeftFields); |
||
| 257 | |||
| 258 | // ________________ 6) Actions and required fields creation + Final Form construction |
||
| 259 | |||
| 260 | $nextButton = new FormAction('saveAddress', _t('OrderForm.NEXT', 'Next')); |
||
| 261 | $nextButton->addExtraClass('next'); |
||
| 262 | $actions = FieldList::create($nextButton); |
||
| 263 | |||
| 264 | $validator = OrderFormAddress_Validator::create($requiredFields); |
||
| 265 | |||
| 266 | parent::__construct($controller, $name, $fields, $actions, $validator); |
||
| 267 | $this->setAttribute('autocomplete', 'off'); |
||
| 268 | //extensions need to be set after __construct |
||
| 269 | //extension point |
||
| 270 | $this->extend('updateFields', $fields); |
||
| 271 | $this->setFields($fields); |
||
| 272 | $this->extend('updateActions', $actions); |
||
| 273 | $this->setActions($actions); |
||
| 274 | $this->extend('updateValidator', $validator); |
||
| 275 | $this->setValidator($validator); |
||
| 276 | |||
| 277 | //this needs to come after the extension calls |
||
| 278 | foreach ($validator->getRequired() as $requiredField) { |
||
| 279 | $field = $fields->dataFieldByName($requiredField); |
||
| 280 | if ($field) { |
||
| 281 | $field->addExtraClass('required'); |
||
| 282 | } |
||
| 283 | } |
||
| 284 | |||
| 285 | // ________________ 7) Load saved data |
||
| 286 | |||
| 287 | //we do this first so that Billing and Shipping Address can override this... |
||
| 288 | if ($this->orderMember) { |
||
| 289 | $this->loadDataFrom($this->orderMember); |
||
| 290 | } |
||
| 291 | |||
| 292 | if ($this->order) { |
||
| 293 | $this->loadDataFrom($this->order); |
||
| 294 | if ($billingAddress) { |
||
| 295 | $this->loadDataFrom($billingAddress); |
||
| 296 | } |
||
| 297 | if (EcommerceConfig::get('OrderAddress', 'use_separate_shipping_address')) { |
||
| 298 | if ($shippingAddress) { |
||
| 299 | $this->loadDataFrom($shippingAddress); |
||
|
0 ignored issues
–
show
The variable
$shippingAddress 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
Loading history...
|
|||
| 300 | } |
||
| 301 | } |
||
| 302 | } |
||
| 303 | |||
| 304 | //allow updating via decoration |
||
| 305 | $oldData = Session::get("FormInfo.{$this->FormName()}.data"); |
||
| 306 | if ($oldData && (is_array($oldData) || is_object($oldData))) { |
||
| 307 | $this->loadDataFrom($oldData); |
||
|
0 ignored issues
–
show
It seems like
$oldData can also be of type object; however, Form::loadDataFrom() does only seem to accept array|object<DataObject>, 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...
|
|||
| 308 | } |
||
| 309 | |||
| 310 | $this->extend('updateOrderFormAddress', $this); |
||
| 311 | } |
||
| 312 | |||
| 313 | /** |
||
| 314 | * Is there a member that is fully operational? |
||
| 315 | * - saved |
||
| 316 | * - has password. |
||
| 317 | * |
||
| 318 | * @return bool |
||
|
0 ignored issues
–
show
|
|||
| 319 | */ |
||
| 320 | protected function orderHasFullyOperationalMember() |
||
| 321 | { |
||
| 322 | //orderMember is Created in __CONSTRUCT |
||
| 323 | if ($this->orderMember) { |
||
| 324 | if ($this->orderMember->exists()) { |
||
| 325 | if ($this->orderMember->Password) { |
||
| 326 | return true; |
||
| 327 | } |
||
| 328 | } |
||
| 329 | } |
||
| 330 | } |
||
| 331 | |||
| 332 | /** |
||
| 333 | * Opposite of orderHasFullyOperationalMember method. |
||
| 334 | * |
||
| 335 | * @return bool |
||
| 336 | */ |
||
| 337 | protected function orderDoesNotHaveFullyOperationalMember() |
||
| 338 | { |
||
| 339 | return $this->orderHasFullyOperationalMember() ? false : true; |
||
| 340 | } |
||
| 341 | |||
| 342 | /** |
||
| 343 | * Process the items in the shopping cart from session, |
||
| 344 | * creating a new {@link Order} record, and updating the |
||
| 345 | * customer's details {@link Member} record. |
||
| 346 | * |
||
| 347 | * {@link Payment} instance is created, linked to the order, |
||
| 348 | * and payment is processed {@link Payment::processPayment()} |
||
| 349 | * |
||
| 350 | * @param array $data Form request data submitted from OrderForm |
||
| 351 | * @param Form $form Form object for this action |
||
| 352 | * @param HTTPRequest $request Request object for this action |
||
|
0 ignored issues
–
show
Should the type for parameter
$request not be SS_HTTPRequest?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. Loading history...
|
|||
| 353 | */ |
||
| 354 | public function saveAddress(array $data, Form $form, SS_HTTPRequest $request) |
||
| 355 | { |
||
| 356 | $this->saveAddressDetails($data, $form, $request); |
||
| 357 | |||
| 358 | $nextStepLink = CheckoutPage::find_next_step_link('orderformaddress'); |
||
| 359 | $this->controller->redirect($nextStepLink); |
||
| 360 | |||
| 361 | return true; |
||
| 362 | } |
||
| 363 | |||
| 364 | /** |
||
| 365 | * Process the items in the shopping cart from session, |
||
| 366 | * creating a new {@link Order} record, and updating the |
||
| 367 | * customer's details {@link Member} record. |
||
| 368 | * |
||
| 369 | * {@link Payment} instance is created, linked to the order, |
||
| 370 | * and payment is processed {@link Payment::processPayment()} |
||
| 371 | * |
||
| 372 | * @param array $data Form request data submitted from OrderForm |
||
| 373 | * @param Form $form Form object for this action |
||
| 374 | * @param HTTPRequest $request Request object for this action |
||
|
0 ignored issues
–
show
Should the type for parameter
$request not be SS_HTTPRequest?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. Loading history...
|
|||
| 375 | */ |
||
| 376 | public function saveAddressDetails(array $data, Form $form, SS_HTTPRequest $request) |
||
|
0 ignored issues
–
show
|
|||
| 377 | { |
||
| 378 | Session::set('BillingEcommerceGeocodingFieldValue', empty($data['BillingEcommerceGeocodingField']) ? null : $data['BillingEcommerceGeocodingField']); |
||
| 379 | Session::set('ShippingEcommerceGeocodingFieldValue', empty($data['ShippingEcommerceGeocodingField']) ? null : $data['ShippingEcommerceGeocodingField']); |
||
| 380 | $this->saveDataToSession(); |
||
| 381 | |||
| 382 | $data = Convert::raw2sql($data); |
||
| 383 | //check for cart items |
||
| 384 | if (!$this->order) { |
||
| 385 | $form->sessionMessage(_t('OrderForm.ORDERNOTFOUND', 'Your order could not be found.'), 'bad'); |
||
| 386 | $this->controller->redirectBack(); |
||
| 387 | |||
| 388 | return false; |
||
| 389 | } |
||
| 390 | if ($this->order && ($this->order->TotalItems($recalculate = true) < 1)) { |
||
| 391 | // WE DO NOT NEED THE THING BELOW BECAUSE IT IS ALREADY IN THE TEMPLATE AND IT CAN LEAD TO SHOWING ORDER WITH ITEMS AND MESSAGE |
||
| 392 | $form->sessionMessage(_t('OrderForm.NOITEMSINCART', 'Please add some items to your cart.'), 'bad'); |
||
| 393 | $this->controller->redirectBack(); |
||
| 394 | |||
| 395 | return false; |
||
| 396 | } |
||
| 397 | |||
| 398 | //----------- START BY SAVING INTO ORDER |
||
| 399 | $form->saveInto($this->order); |
||
| 400 | //----------- -------------------------------- |
||
| 401 | |||
| 402 | //MEMBER |
||
| 403 | $this->orderMember = $this->createOrFindMember($data); |
||
|
0 ignored issues
–
show
It seems like
$data defined by \Convert::raw2sql($data) on line 382 can also be of type string; however, OrderFormAddress::createOrFindMember() 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...
|
|||
| 404 | if ($this->debug) { |
||
| 405 | debug::log('debug array from OrderFormAddress:'.implode("\r\n<hr />", $this->debugArray)); |
||
| 406 | } |
||
| 407 | |||
| 408 | if ($this->orderMember && is_object($this->orderMember)) { |
||
| 409 | if ($this->memberShouldBeSaved($data)) { |
||
|
0 ignored issues
–
show
It seems like
$data defined by \Convert::raw2sql($data) on line 382 can also be of type string; however, OrderFormAddress::memberShouldBeSaved() 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...
|
|||
| 410 | $form->saveInto($this->orderMember); |
||
| 411 | $password = $this->validPasswordHasBeenEntered($data); |
||
| 412 | if ($password) { |
||
| 413 | $this->orderMember->changePassword($password); |
||
|
0 ignored issues
–
show
It seems like
$password defined by $this->validPasswordHasBeenEntered($data) on line 411 can also be of type array; however, Member::changePassword() does only seem to accept string, 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...
|
|||
| 414 | } |
||
| 415 | $this->orderMember->write(); |
||
| 416 | } |
||
| 417 | if ($this->memberShouldBeLoggedIn($data)) { |
||
|
0 ignored issues
–
show
It seems like
$data defined by \Convert::raw2sql($data) on line 382 can also be of type string; however, OrderFormAddress::memberShouldBeLoggedIn() 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...
|
|||
| 418 | $this->orderMember->LogIn(); |
||
| 419 | } |
||
| 420 | //this causes ERRORS .... |
||
| 421 | $this->order->MemberID = $this->orderMember->ID; |
||
|
0 ignored issues
–
show
The property
MemberID does not exist on object<Order>. Since you implemented __set, maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property. Loading history...
|
|||
| 422 | Session::set('Ecommerce_Member_For_Order', $this->orderMember->ID); |
||
| 423 | } |
||
| 424 | |||
| 425 | //BILLING ADDRESS |
||
| 426 | if ($billingAddress = $this->order->CreateOrReturnExistingAddress('BillingAddress')) { |
||
| 427 | $form->saveInto($billingAddress); |
||
| 428 | // NOTE: write should return the new ID of the object |
||
| 429 | $this->order->BillingAddressID = $billingAddress->write(); |
||
|
0 ignored issues
–
show
The property
BillingAddressID does not exist on object<Order>. Since you implemented __set, maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property. Loading history...
|
|||
| 430 | } |
||
| 431 | |||
| 432 | // SHIPPING ADDRESS |
||
| 433 | if (isset($data['UseShippingAddress'])) { |
||
| 434 | if ($data['UseShippingAddress']) { |
||
| 435 | if ($shippingAddress = $this->order->CreateOrReturnExistingAddress('ShippingAddress')) { |
||
| 436 | $form->saveInto($shippingAddress); |
||
| 437 | // NOTE: write should return the new ID of the object |
||
| 438 | $this->order->ShippingAddressID = $shippingAddress->write(); |
||
|
0 ignored issues
–
show
The property
ShippingAddressID does not exist on object<Order>. Since you implemented __set, maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property. Loading history...
|
|||
| 439 | } |
||
| 440 | } |
||
| 441 | } |
||
| 442 | |||
| 443 | $this->extend('saveAddressExtension', $data, $form, $order, $this->orderMember); |
||
| 444 | |||
| 445 | //SAVE ORDER |
||
| 446 | $this->order->write(); |
||
| 447 | |||
| 448 | //----------------- CLEAR OLD DATA ------------------------------ |
||
| 449 | $this->clearSessionData(); //clears the stored session form data that might have been needed if validation failed |
||
| 450 | //----------------------------------------------- |
||
| 451 | return true; |
||
| 452 | } |
||
| 453 | |||
| 454 | /** |
||
| 455 | * saves the form into session. |
||
| 456 | * |
||
| 457 | * @param array $data - data from form. |
||
|
0 ignored issues
–
show
There is no parameter named
$data. Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. Loading history...
|
|||
| 458 | */ |
||
| 459 | public function saveDataToSession() |
||
| 460 | { |
||
| 461 | $data = $this->getData(); |
||
| 462 | unset($data['AccountInfo']); |
||
| 463 | unset($data['LoginDetails']); |
||
| 464 | unset($data['LoggedInAsNote']); |
||
| 465 | unset($data['PasswordCheck1']); |
||
| 466 | unset($data['PasswordCheck2']); |
||
| 467 | Session::set("FormInfo.{$this->FormName()}.data", $data); |
||
|
0 ignored issues
–
show
$data 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...
|
|||
| 468 | } |
||
| 469 | |||
| 470 | /** |
||
| 471 | * clear the form data (after the form has been submitted and processed). |
||
| 472 | */ |
||
| 473 | public function clearSessionData() |
||
| 474 | { |
||
| 475 | $this->clearMessage(); |
||
| 476 | Session::set("FormInfo.{$this->FormName()}.data", null); |
||
| 477 | } |
||
| 478 | |||
| 479 | /** |
||
| 480 | * Works out the most likely member for the order after submission of the form. |
||
| 481 | * It returns a member if appropriate. |
||
| 482 | * 1. does the order already have a member that is not a shop-admin - if so - DONE. |
||
| 483 | * 2. shop allows creation of member? - if NOT return NULL |
||
| 484 | * A. is the logged in member the shop admin placing an order on behalf of someone else? |
||
| 485 | * A1. is the email entered different from the admin email? |
||
| 486 | * A2. attach to other member as new one or existing one. |
||
| 487 | * 3. can the entered data be used? - if |
||
| 488 | * 4. is there no member logged in yet? - If there is one return null, member is already linked to order. |
||
| 489 | * 5. find member from data entered (even if not logged in) |
||
| 490 | * 6. At this stage, if we dont have a member, we will create one! |
||
| 491 | * 7. We do one last check to see if we are allowed to create one. |
||
| 492 | * |
||
| 493 | * @param array - form data - should include $data[uniqueField....] - e.g. $data["Email"] |
||
| 494 | * |
||
| 495 | * @return Member | Null |
||
| 496 | **/ |
||
| 497 | protected function createOrFindMember(array $data) |
||
| 498 | { |
||
| 499 | //get the best available from order. |
||
| 500 | $this->orderMember = $this->order->CreateOrReturnExistingMember(false); |
||
| 501 | $orderPlacedByShopAdmin = ($this->loggedInMember && $this->loggedInMember->IsShopAdmin()) ? true : false; |
||
| 502 | //1. does the order already have a member |
||
| 503 | if ($this->orderMember->exists() && !$orderPlacedByShopAdmin) { |
||
| 504 | if ($this->debug) { |
||
| 505 | $this->debugArray[] = '1. the order already has a member'; |
||
| 506 | } |
||
| 507 | } else { |
||
| 508 | //special shop admin situation: |
||
| 509 | if ($orderPlacedByShopAdmin) { |
||
| 510 | if ($this->debug) { |
||
| 511 | $this->debugArray[] = 'A1. shop admin places order '; |
||
| 512 | } |
||
| 513 | //2. does email match shopadmin email |
||
| 514 | if ($newEmail = $this->enteredEmailAddressDoesNotMatchLoggedInUser($data)) { |
||
| 515 | $this->orderMember = null; |
||
| 516 | if ($this->debug) { |
||
| 517 | $this->debugArray[] = 'A2. email does not match shopadmin email - reset orderMember'; |
||
| 518 | } |
||
| 519 | $this->orderMember = $this->anotherExistingMemberWithSameUniqueFieldValue($data); |
||
| 520 | if ($this->orderMember) { |
||
| 521 | if ($this->debug) { |
||
| 522 | $this->debugArray[] = 'A3. the other member already exists'; |
||
| 523 | } |
||
| 524 | } elseif ($this->memberShouldBeCreated($data)) { |
||
| 525 | if ($this->debug) { |
||
| 526 | $this->debugArray[] = 'A4. No other member found - creating new one'; |
||
| 527 | } |
||
| 528 | $this->orderMember = Member::create(); |
||
| 529 | $this->orderMember->Email = Convert::raw2sql($newEmail); |
||
| 530 | $this->orderMember->write($forceCreation = true); |
||
| 531 | $this->newlyCreatedMemberID = $this->orderMember->ID; |
||
| 532 | } |
||
| 533 | } |
||
| 534 | } else { |
||
| 535 | if ($this->debug) { |
||
| 536 | $this->debugArray[] = '2. shop allows creation of member'; |
||
| 537 | } |
||
| 538 | $this->orderMember = null; |
||
| 539 | |||
| 540 | //3. can the entered data be used? |
||
| 541 | //member that will be added does not exist somewhere else. |
||
| 542 | if ($this->uniqueMemberFieldCanBeUsed($data)) { |
||
| 543 | if ($this->debug) { |
||
| 544 | $this->debugArray[] = '3. can the entered data be used?'; |
||
| 545 | } |
||
| 546 | // 4. is there no member logged in yet? |
||
| 547 | //no logged in member |
||
| 548 | if (!$this->loggedInMember) { |
||
| 549 | if ($this->debug) { |
||
| 550 | $this->debugArray[] = '4. is there no member logged in yet?'; |
||
| 551 | } |
||
| 552 | //5. find member from data entered (even if not logged in) |
||
| 553 | //another member with the same email? |
||
| 554 | |||
| 555 | if ($this->debug) { |
||
| 556 | $this->debugArray[] = '5. find member from data entered (even if not logged in)'; |
||
| 557 | } |
||
| 558 | $this->orderMember = $this->anotherExistingMemberWithSameUniqueFieldValue($data); |
||
| 559 | |||
| 560 | //6. At this stage, if we dont have a member, we will create one! |
||
| 561 | //in case we still dont have a member AND we should create a member for every customer, then we do this below... |
||
| 562 | if (!$this->orderMember) { |
||
| 563 | if ($this->debug) { |
||
| 564 | $this->debugArray[] = '6. No other member found'; |
||
| 565 | } |
||
| 566 | // 7. We do one last check to see if we are allowed to create one |
||
| 567 | //are we allowed to create a member? |
||
| 568 | if ($this->memberShouldBeCreated($data)) { |
||
| 569 | if ($this->debug) { |
||
| 570 | $this->debugArray[] = '7. We do one last check to see if we are allowed to create one. CREATE NEW MEMBER'; |
||
| 571 | } |
||
| 572 | $this->orderMember = $this->order->CreateOrReturnExistingMember(false); |
||
| 573 | $this->orderMember->write($forceCreation = true); |
||
| 574 | //this is safe because it is memberShouldBeCreated ... |
||
| 575 | $this->newlyCreatedMemberID = $this->orderMember->ID; |
||
| 576 | } |
||
| 577 | } |
||
| 578 | } |
||
| 579 | } |
||
| 580 | } |
||
| 581 | } |
||
| 582 | |||
| 583 | return $this->orderMember; |
||
| 584 | } |
||
| 585 | |||
| 586 | /** |
||
| 587 | * Should a new member be created? |
||
| 588 | * |
||
| 589 | * @Todo: explain why password needs to be more than three characters... |
||
| 590 | * @todo: create class that checks if password is good enough |
||
| 591 | * |
||
| 592 | * @param array - form data - should include $data[uniqueField....] - e.g. $data["Email"] |
||
| 593 | * |
||
| 594 | * @return bool |
||
| 595 | **/ |
||
| 596 | protected function memberShouldBeCreated(array $data) |
||
| 597 | { |
||
| 598 | //shop admin and |
||
| 599 | //data entered does not match shop admin and |
||
| 600 | //data entered does not match existing member... |
||
| 601 | //TRUE! |
||
| 602 | if ($this->loggedInMember && $this->loggedInMember->IsShopAdmin()) { |
||
| 603 | if ($this->enteredEmailAddressDoesNotMatchLoggedInUser($data)) { |
||
| 604 | if ($this->anotherExistingMemberWithSameUniqueFieldValue($data)) { |
||
|
0 ignored issues
–
show
|
|||
| 605 | return false; |
||
| 606 | } else { |
||
| 607 | return true; |
||
| 608 | } |
||
| 609 | } |
||
| 610 | } |
||
| 611 | // already logged in or already created... |
||
| 612 | // FALSE! |
||
| 613 | elseif ($this->loggedInMember || $this->newlyCreatedMemberID) { |
||
| 614 | return false; |
||
| 615 | } |
||
| 616 | // no other user exists with the email... |
||
| 617 | // TRUE! |
||
| 618 | else { |
||
| 619 | if ($this->anotherExistingMemberWithSameUniqueFieldValue($data)) { |
||
|
0 ignored issues
–
show
|
|||
| 620 | return false; |
||
| 621 | } else { |
||
| 622 | return true; |
||
| 623 | } |
||
| 624 | } |
||
| 625 | //defaults to FALSE... |
||
| 626 | return false; |
||
| 627 | } |
||
| 628 | |||
| 629 | /** |
||
| 630 | * @param array - form data - should include $data[uniqueField....] - e.g. $data["Email"] |
||
| 631 | * |
||
| 632 | * @return bool |
||
| 633 | **/ |
||
| 634 | protected function memberShouldBeSaved(array $data) |
||
| 635 | { |
||
| 636 | |||
| 637 | //new members always need to be saved |
||
| 638 | $newMember = ( |
||
| 639 | $this->memberShouldBeCreated($data) || |
||
| 640 | $this->newlyCreatedMemberID |
||
| 641 | ) ? true : false; |
||
| 642 | |||
| 643 | // existing logged in members need to be saved if they are updateable |
||
| 644 | // AND do not match someone else... |
||
| 645 | $updateableMember = ( |
||
| 646 | $this->loggedInMember && |
||
| 647 | !$this->anotherExistingMemberWithSameUniqueFieldValue($data) && |
||
| 648 | EcommerceConfig::get('EcommerceRole', 'automatically_update_member_details') |
||
| 649 | ) ? true : false; |
||
| 650 | |||
| 651 | // logged in member is shop admin and members are updateable... |
||
| 652 | $memberIsShopAdmin = ( |
||
| 653 | $this->loggedInMember && |
||
| 654 | $this->loggedInMember->IsShopAdmin() && |
||
| 655 | EcommerceConfig::get('EcommerceRole', 'automatically_update_member_details') |
||
| 656 | ) ? true : false; |
||
| 657 | if ($newMember || $updateableMember || $memberIsShopAdmin) { |
||
|
0 ignored issues
–
show
|
|||
| 658 | return true; |
||
| 659 | } |
||
| 660 | |||
| 661 | return false; |
||
| 662 | } |
||
| 663 | |||
| 664 | /** |
||
| 665 | * returns TRUE if |
||
| 666 | * - the member is not logged in |
||
| 667 | * - the member is new AND |
||
| 668 | * - the password is valid. |
||
| 669 | * |
||
| 670 | * @param array - form data - should include $data[uniqueField....] - e.g. $data["Email"] |
||
| 671 | * |
||
| 672 | * @return bool |
||
| 673 | **/ |
||
| 674 | protected function memberShouldBeLoggedIn(array $data) |
||
| 675 | { |
||
| 676 | if (!$this->loggedInMember) { |
||
| 677 | if ($this->newlyCreatedMemberID && $this->validPasswordHasBeenEntered($data)) { |
||
| 678 | return true; |
||
| 679 | } |
||
| 680 | } |
||
| 681 | |||
| 682 | return false; |
||
| 683 | } |
||
| 684 | |||
| 685 | /** |
||
| 686 | * returns TRUE if |
||
| 687 | * - there is no existing member with the same value in the unique field |
||
| 688 | * - OR the member is not logged in. |
||
| 689 | * - OR the member is a Shop Admin (we assume they are placing an order on behalf of someone else). |
||
| 690 | * returns FALSE if |
||
| 691 | * - the unique field already exists in another member |
||
| 692 | * - AND the member being "tested" is already logged in... |
||
| 693 | * in that case the logged in member tries to take on another identity. |
||
| 694 | * If you are not logged BUT the the unique field is used by an existing member then we can still |
||
| 695 | * use the field - we just CAN NOT log in the member. |
||
| 696 | * This method needs to be public because it is used by the OrderForm_Validator (see below). |
||
| 697 | * |
||
| 698 | * @param array - form data - should include $data[uniqueField....] - e.g. $data["Email"] |
||
| 699 | * |
||
| 700 | * @return bool |
||
| 701 | **/ |
||
| 702 | public function uniqueMemberFieldCanBeUsed(array $data) |
||
| 703 | { |
||
| 704 | if ($this->loggedInMember && $this->anotherExistingMemberWithSameUniqueFieldValue($data)) { |
||
| 705 | //there is an exception for shop admins |
||
| 706 | //who can place an order on behalve of a customer. |
||
| 707 | if ($this->loggedInMember->IsShopAdmin()) { |
||
| 708 | //REMOVED PART: |
||
| 709 | //but NOT when the member placing the Order is the ShopAdmin |
||
| 710 | //AND there is another member with the same credentials. |
||
| 711 | //because in that case the ShopAdmin is not placing an order |
||
| 712 | //on behalf of someone else. |
||
| 713 | //that is, |
||
| 714 | //if($this->orderMember->ID == $this->loggedInMember->ID) { |
||
| 715 | // return false; |
||
| 716 | //} |
||
| 717 | } else { |
||
| 718 | return false; |
||
| 719 | } |
||
| 720 | } |
||
| 721 | |||
| 722 | return true; |
||
| 723 | } |
||
| 724 | |||
| 725 | /** |
||
| 726 | * returns existing member if it already exists and it is not the logged-in one. |
||
| 727 | * Based on the unique field (email)). |
||
| 728 | * |
||
| 729 | * @param array - form data - should include $data[uniqueField....] - e.g. $data["Email"] |
||
| 730 | **/ |
||
| 731 | protected function anotherExistingMemberWithSameUniqueFieldValue(array $data) |
||
|
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a Loading history...
|
|||
| 732 | { |
||
| 733 | $uniqueFieldName = Member::get_unique_identifier_field(); |
||
|
0 ignored issues
–
show
The method
Member::get_unique_identifier_field() has been deprecated with message: 4.0 Use the "Member.unique_identifier_field" config setting instead
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead. Loading history...
|
|||
| 734 | //The check below covers both Scenario 3 and 4.... |
||
| 735 | if (isset($data[$uniqueFieldName])) { |
||
| 736 | if ($this->loggedInMember) { |
||
| 737 | $currentUserID = $this->loggedInMember->ID; |
||
| 738 | } else { |
||
| 739 | $currentUserID = 0; |
||
| 740 | } |
||
| 741 | $uniqueFieldValue = $data[$uniqueFieldName]; |
||
| 742 | //no need to convert raw2sql as this has already been done. |
||
| 743 | return Member::get() |
||
| 744 | ->filter( |
||
| 745 | array( |
||
| 746 | $uniqueFieldName => $uniqueFieldValue, |
||
| 747 | ) |
||
| 748 | ) |
||
| 749 | ->exclude( |
||
| 750 | array( |
||
| 751 | 'ID' => $currentUserID, |
||
| 752 | ) |
||
| 753 | ) |
||
| 754 | ->First(); |
||
| 755 | } |
||
| 756 | user_error('No email data was set, suspicious transaction', E_USER_WARNING); |
||
| 757 | |||
| 758 | return; |
||
| 759 | } |
||
| 760 | |||
| 761 | /** |
||
| 762 | * returns the email if |
||
| 763 | * - user is logged in already |
||
| 764 | * - user's email in DB does not match email entered. |
||
| 765 | * |
||
| 766 | * @param array |
||
| 767 | * |
||
| 768 | * @return string | false |
||
| 769 | */ |
||
| 770 | protected function enteredEmailAddressDoesNotMatchLoggedInUser($data) |
||
| 771 | { |
||
| 772 | if ($this->loggedInMember) { |
||
| 773 | $DBUniqueFieldName = $this->loggedInMember->Email; |
||
| 774 | if ($DBUniqueFieldName) { |
||
| 775 | $uniqueFieldName = Member::get_unique_identifier_field(); |
||
|
0 ignored issues
–
show
The method
Member::get_unique_identifier_field() has been deprecated with message: 4.0 Use the "Member.unique_identifier_field" config setting instead
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead. Loading history...
|
|||
| 776 | if (isset($data[$uniqueFieldName])) { |
||
| 777 | $enteredUniqueFieldName = $data[$uniqueFieldName]; |
||
| 778 | if ($enteredUniqueFieldName) { |
||
| 779 | if ($DBUniqueFieldName != $enteredUniqueFieldName) { |
||
| 780 | return $enteredUniqueFieldName; |
||
| 781 | } |
||
| 782 | } |
||
| 783 | } |
||
| 784 | } |
||
| 785 | } |
||
| 786 | |||
| 787 | return false; |
||
| 788 | } |
||
| 789 | |||
| 790 | /** |
||
| 791 | * Check if the password is good enough. |
||
| 792 | * |
||
| 793 | * @param data (from form) |
||
| 794 | * |
||
| 795 | * @return string |
||
|
0 ignored issues
–
show
|
|||
| 796 | */ |
||
| 797 | protected function validPasswordHasBeenEntered($data) |
||
| 798 | { |
||
| 799 | return ShopAccountForm_PasswordValidator::clean_password($data); |
||
| 800 | } |
||
| 801 | } |
||
| 802 |
Since your code implements the magic getter
_get, this function will be called for any read access on an undefined variable. You can add the@propertyannotation to your class or interface to document the existence of this variable.If the property has read access only, you can use the @property-read annotation instead.
Of course, you may also just have mistyped another name, in which case you should fix the error.
See also the PhpDoc documentation for @property.