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 | * @author Nicolaas [at] sunnysideup.co.nz |
||
5 | * @package: ecommerce |
||
6 | * @sub-package: ecommerce_delivery |
||
7 | * @description: Shipping calculation scheme based on SimpleShippingModifier. |
||
8 | * It lets you set fixed shipping costs, or a fixed |
||
9 | * cost for each region you're delivering to. |
||
10 | */ |
||
11 | class PickUpOrDeliveryModifier extends OrderModifier |
||
0 ignored issues
–
show
|
|||
12 | { |
||
13 | |||
14 | // ######################################## *** model defining static variables (e.g. $db, $has_one) |
||
15 | |||
16 | private static $db = array( |
||
0 ignored issues
–
show
|
|||
17 | "TotalWeight" => "Double", |
||
18 | "RegionAndCountry" => "Varchar", |
||
19 | "SerializedCalculationObject" => "Text", |
||
20 | "DebugString" => "HTMLText", |
||
21 | "SubTotalAmount" => "Currency" |
||
22 | ); |
||
23 | |||
24 | private static $has_one = array( |
||
0 ignored issues
–
show
|
|||
25 | "Option" => "PickUpOrDeliveryModifierOptions" |
||
26 | ); |
||
27 | |||
28 | private static $singular_name = "Pickup / Delivery Charge"; |
||
0 ignored issues
–
show
|
|||
29 | public function i18n_singular_name() |
||
30 | { |
||
31 | return _t("PickUpOrDeliveryModifier.DELIVERYCHARGE", "Delivery / Pick-up"); |
||
32 | } |
||
33 | |||
34 | private static $plural_name = "Pickup / Delivery Charges"; |
||
0 ignored issues
–
show
|
|||
35 | public function i18n_plural_name() |
||
36 | { |
||
37 | return _t("PickUpOrDeliveryModifier.DELIVERYCHARGES", "Delivery / Pick-up"); |
||
38 | } |
||
39 | |||
40 | private static $include_form_in_order_table = true; |
||
0 ignored issues
–
show
|
|||
41 | |||
42 | |||
43 | // ######################################## *** cms variables + functions (e.g. getCMSFields, $searchableFields) |
||
44 | |||
45 | public function getCMSFields() |
||
46 | { |
||
47 | $fields = parent::getCMSFields(); |
||
48 | //debug fields |
||
49 | $fields->removeByName("TotalWeight"); |
||
50 | $fields->addFieldToTab("Root.Debug", new ReadonlyField("TotalWeightShown", "total weight used for calculation", $this->TotalWeight)); |
||
0 ignored issues
–
show
The property
TotalWeight does not exist on object<PickUpOrDeliveryModifier> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?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.");
}
}
}
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. ![]() |
|||
51 | $fields->removeByName("SubTotalAmount"); |
||
52 | $fields->addFieldToTab("Root.Debug", new ReadonlyField("SubTotalAmountShown", "sub-total amount used for calculation", $this->SubTotalAmount)); |
||
0 ignored issues
–
show
The property
SubTotalAmount does not exist on object<PickUpOrDeliveryModifier> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?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.");
}
}
}
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. ![]() |
|||
53 | $fields->removeByName("SerializedCalculationObject"); |
||
54 | $fields->addFieldToTab("Root.Debug", new ReadonlyField("SerializedCalculationObjectShown", "debug data", unserialize($this->SerializedCalculationObject))); |
||
0 ignored issues
–
show
The property
SerializedCalculationObject does not exist on object<PickUpOrDeliveryModifier> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?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.");
}
}
}
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. ![]() |
|||
55 | $fields->removeByName("DebugString"); |
||
56 | $fields->addFieldToTab("Root.Debug", new ReadonlyField("DebugStringShown", "steps taken", $this->DebugString)); |
||
0 ignored issues
–
show
The property
DebugString does not exist on object<PickUpOrDeliveryModifier> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?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.");
}
}
}
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. ![]() |
|||
57 | return $fields; |
||
58 | } |
||
59 | |||
60 | |||
61 | // ######################################## *** other (non) static variables (e.g. private static $special_name_for_something, protected $order) |
||
62 | |||
63 | /** |
||
64 | *@var String $weight_field - the field used in the Buyable to work out the weight. |
||
65 | * |
||
66 | */ |
||
67 | private static $weight_field = 'Weight'; |
||
0 ignored issues
–
show
|
|||
68 | |||
69 | /** |
||
70 | * @var Float $total_weight |
||
71 | * the total amount of weight for the order |
||
72 | * saved here for speed's sake |
||
73 | */ |
||
74 | private static $_total_weight = null; |
||
75 | |||
76 | /** |
||
77 | * @var DataList |
||
78 | */ |
||
79 | private static $available_options = null; |
||
80 | |||
81 | /** |
||
82 | * @var PickUpOrDeliveryModifierOptions |
||
83 | * The most applicable option |
||
84 | */ |
||
85 | private static $selected_option = null; |
||
86 | |||
87 | /** |
||
88 | * @var Double |
||
89 | * the total amount charged in the end. |
||
90 | * saved here for speed's sake |
||
91 | */ |
||
92 | private static $_actual_charges = 0; |
||
93 | |||
94 | /** |
||
95 | * @var Boolean |
||
96 | * the total amount charged in the end |
||
97 | * saved here for speed's sake |
||
98 | */ |
||
99 | private static $calculations_done = false; |
||
100 | |||
101 | /** |
||
102 | * @var String |
||
103 | * Debugging tool |
||
104 | */ |
||
105 | protected $debugMessage = ""; |
||
106 | |||
107 | // ######################################## *** CRUD functions (e.g. canEdit) |
||
108 | |||
109 | // ######################################## *** init and update functions |
||
110 | |||
111 | /** |
||
112 | * set the selected option (selected by user using form) |
||
113 | * @param Int $optionID |
||
114 | */ |
||
115 | public function setOption($optionID) |
||
116 | { |
||
117 | $optionID = intval($optionID); |
||
118 | $this->OptionID = $optionID; |
||
0 ignored issues
–
show
The property
OptionID does not exist on object<PickUpOrDeliveryModifier> . 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. ![]() |
|||
119 | $this->write(); |
||
120 | } |
||
121 | |||
122 | /** |
||
123 | * updates database fields |
||
124 | * @param Bool $force - run it, even if it has run already |
||
125 | * @return void |
||
126 | */ |
||
127 | public function runUpdate($force = true) |
||
128 | { |
||
129 | $this->debugMessage = ""; |
||
130 | self::$calculations_done = false; |
||
131 | self::$selected_option = null; |
||
132 | self::$available_options = null; |
||
133 | $this->checkField("OptionID"); |
||
134 | $this->checkField("SerializedCalculationObject"); |
||
135 | $this->checkField("TotalWeight"); |
||
136 | $this->checkField("SubTotalAmount"); |
||
137 | $this->checkField("RegionAndCountry"); |
||
138 | $this->checkField("CalculatedTotal"); |
||
139 | $this->checkField("DebugString"); |
||
140 | parent::runUpdate($force); |
||
141 | } |
||
142 | |||
143 | // ######################################## *** form functions (e. g. Showform and getform) |
||
144 | |||
145 | |||
146 | |||
147 | /** |
||
148 | * standard Modifier Method |
||
149 | * @return Boolean |
||
150 | */ |
||
151 | public function ShowForm() |
||
152 | { |
||
153 | if ($this->ShowInTable()) { |
||
154 | if ($this->Order()->Items()) { |
||
155 | if ($options = $this->liveOptions()) { |
||
156 | return $options->count() > 1; |
||
157 | } |
||
158 | } |
||
159 | } |
||
160 | return false; |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * Should the form be included in the editable form |
||
165 | * on the checkout page? |
||
166 | * @return Boolean |
||
167 | */ |
||
168 | public function ShowFormInEditableOrderTable() |
||
169 | { |
||
170 | return ($this->ShowForm() && $this->Config()->get("include_form_in_order_table")) ? true : false; |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * |
||
175 | * @return Form |
||
176 | */ |
||
177 | public function getModifierForm(Controller $optionalController = null, Validator $optionalValidator = null) |
||
178 | { |
||
179 | Requirements::themedCSS("PickUpOrDeliveryModifier", "ecommerce_delivery"); |
||
180 | Requirements::javascript(THIRDPARTY_DIR."/jquery/jquery.js"); |
||
181 | //Requirements::block(THIRDPARTY_DIR."/jquery/jquery.js"); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
56% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
182 | //Requirements::javascript(Director::protocol()."ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
62% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
183 | Requirements::javascript(THIRDPARTY_DIR."/jquery-form/jquery.form.js"); |
||
184 | Requirements::javascript("ecommerce_delivery/javascript/PickUpOrDeliveryModifier.js"); |
||
185 | $array = PickUpOrDeliveryModifierOptions::get_all_as_country_array(); |
||
186 | if ($array && is_array($array) && count($array)) { |
||
0 ignored issues
–
show
The expression
$array of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
187 | $js = "\n".'var PickUpOrDeliveryModifierOptions = []'; |
||
188 | $count = 0; |
||
189 | foreach ($array as $key => $option) { |
||
190 | if ($option && is_array($option) && count($option)) { |
||
191 | if ($count == 0) { |
||
192 | $js .= "\n".' PickUpOrDeliveryModifierOptions["'.$key.'"] = new Array("'.implode('","', $option).'")'; |
||
193 | } else { |
||
194 | $js .= "\n".' PickUpOrDeliveryModifierOptions["'.$key.'"] = new Array("'.implode('","', $option).'")'; |
||
195 | } |
||
196 | $count++; |
||
197 | } |
||
198 | } |
||
199 | if ($js) { |
||
200 | //add final semi-comma |
||
201 | $js .= ""; |
||
202 | Requirements::customScript($js, "PickupOrDeliveryModifier"); |
||
203 | } |
||
204 | } |
||
205 | $fields = new FieldList(); |
||
206 | $fields->push($this->headingField()); |
||
207 | $fields->push($this->descriptionField()); |
||
208 | $options = $this->liveOptions()->map('ID', 'Name');//$this->getOptionListForDropDown(); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
84% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
209 | $optionID = $this->LiveOptionID(); |
||
210 | $fields->push(OptionSetField::create('PickupOrDeliveryType', 'Preference', $options, $optionID)); |
||
211 | $actions = new FieldList( |
||
212 | new FormAction('processOrderModifier', 'Update Pickup / Delivery Option') |
||
213 | ); |
||
214 | return new PickUpOrDeliveryModifier_Form($optionalController, 'PickUpOrDeliveryModifier', $fields, $actions, $optionalValidator); |
||
215 | } |
||
216 | |||
217 | // ######################################## *** template functions (e.g. ShowInTable, TableTitle, etc...) ... USES DB VALUES |
||
218 | |||
219 | /** |
||
220 | * @return Boolean |
||
221 | */ |
||
222 | public function ShowInTable() |
||
223 | { |
||
224 | return true; |
||
225 | } |
||
226 | |||
227 | /** |
||
228 | * @return Boolean |
||
229 | */ |
||
230 | public function CanBeRemoved() |
||
231 | { |
||
232 | return false; |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * NOTE: the function below is HACK and needs fixing proper. |
||
237 | * |
||
238 | */ |
||
239 | public function CartValue() |
||
240 | { |
||
241 | return $this->getCartValue(); |
||
242 | } |
||
243 | public function getCartValue() |
||
244 | { |
||
245 | return $this->LiveCalculatedTotal(); |
||
246 | } |
||
247 | |||
248 | // ######################################## *** inner calculations.... USES CALCULATED VALUES |
||
249 | |||
250 | /** |
||
251 | * returns the current selected option as object |
||
252 | * @return PickUpOrDeliveryModifierOptions; |
||
0 ignored issues
–
show
The doc-type
PickUpOrDeliveryModifierOptions; could not be parsed: Expected "|" or "end of type", but got ";" at position 31. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
253 | */ |
||
254 | protected function liveOptionObject() |
||
255 | { |
||
256 | return PickUpOrDeliveryModifierOptions::get()->byID($this->LiveOptionID()); |
||
257 | } |
||
258 | |||
259 | /** |
||
260 | * works out if Weight is applicable at all |
||
261 | * @return Boolean |
||
262 | */ |
||
263 | protected function useWeight() |
||
264 | { |
||
265 | return EcommerceDBConfig::current_ecommerce_db_config()->ProductsHaveWeight; |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * Returns the available delivery options based on the current country and region |
||
270 | * for the order. |
||
271 | * Must always return something! |
||
272 | * @return DataList |
||
273 | */ |
||
274 | protected function liveOptions() |
||
275 | { |
||
276 | if (!self::$available_options) { |
||
277 | $countryID = EcommerceCountry::get_country_id(); |
||
278 | $regionID = EcommerceRegion::get_region_id(); |
||
279 | $weight = $this->LiveTotalWeight(); |
||
0 ignored issues
–
show
$weight is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
280 | $options = PickUpOrDeliveryModifierOptions::get(); |
||
281 | if ($options->count()) { |
||
282 | foreach ($options as $option) { |
||
283 | //check countries |
||
284 | if ($countryID) { |
||
285 | $availableInCountriesList = $option->AvailableInCountries(); |
||
286 | //exclude if not found in country list |
||
287 | if ($availableInCountriesList->Count() > 0 && ! $availableInCountriesList->find('ID', $countryID)) { |
||
288 | continue; |
||
289 | } |
||
290 | //exclude if in exclusion list |
||
291 | $excludedFromCountryList = $option->ExcludeFromCountries(); |
||
292 | if ($excludedFromCountryList->Count() > 0 && $excludedFromCountryList->find('ID', $countryID)) { |
||
293 | continue; |
||
294 | } |
||
295 | } |
||
296 | //check regions |
||
297 | if ($regionID) { |
||
298 | $optionRegions = $option->AvailableInRegions(); |
||
299 | //exclude if not found in region list |
||
300 | if ($optionRegions->Count() > 0 && ! $optionRegions->find('ID', $regionID)) { |
||
301 | continue; |
||
302 | } |
||
303 | } |
||
304 | $result[] = $option; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$result was never initialized. Although not strictly required by PHP, it is generally a good practice to add $result = 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 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. ![]() |
|||
305 | } |
||
306 | } |
||
307 | if (! isset($result)) { |
||
308 | $result[] = PickUpOrDeliveryModifierOptions::default_object(); |
||
0 ignored issues
–
show
The variable
$result 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
![]() |
|||
309 | } |
||
310 | self::$available_options = new ArrayList($result); |
||
0 ignored issues
–
show
It seems like
new \ArrayList($result) of type object<ArrayList> is incompatible with the declared type object<DataList> of property $available_options .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||
311 | } |
||
312 | return self::$available_options; |
||
313 | } |
||
314 | |||
315 | |||
316 | // ######################################## *** calculate database fields: protected function Live[field name] ... USES CALCULATED VALUES |
||
317 | |||
318 | /** |
||
319 | * Precondition : There are always options available. |
||
320 | * @return Int |
||
321 | */ |
||
322 | protected function LiveOptionID() |
||
323 | { |
||
324 | if (!self::$selected_option) { |
||
325 | $options = $this->liveOptions(); |
||
326 | if (self::$selected_option = $options->find('ID', $this->OptionID)) { |
||
0 ignored issues
–
show
The property
OptionID does not exist on object<PickUpOrDeliveryModifier> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?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.");
}
}
}
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. ![]() It seems like
$options->find('ID', $this->OptionID) can also be of type object<DataObject> . However, the property $selected_option is declared as type object<PickUpOrDeliveryModifierOptions> . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() This
if statement is empty and can be removed.
This check looks for the bodies of These if (rand(1, 6) > 3) {
//print "Check failed";
} else {
print "Check succeeded";
}
could be turned into if (rand(1, 6) <= 3) {
print "Check succeeded";
}
This is much more concise to read. ![]() |
|||
327 | //do nothing; |
||
328 | } else { |
||
329 | self::$selected_option = $options->find('IsDefault', 1); |
||
0 ignored issues
–
show
Are you sure the assignment to
self::$selected_option is correct as $options->find('IsDefault', 1) (which targets DataList::find() ) seems to always return null.
This check looks for function or method calls that always return null and whose return value is assigned to a variable. class A
{
function getObject()
{
return null;
}
}
$a = new A();
$object = $a->getObject();
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||
330 | if (! self::$selected_option) { |
||
331 | self::$selected_option = $options->First(); |
||
0 ignored issues
–
show
It seems like
$options->First() can also be of type object<DataObject> . However, the property $selected_option is declared as type object<PickUpOrDeliveryModifierOptions> . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
332 | } |
||
333 | } |
||
334 | } |
||
335 | return self::$selected_option->ID; |
||
336 | } |
||
337 | |||
338 | /** |
||
339 | * @return String |
||
340 | */ |
||
341 | protected function LiveName() |
||
342 | { |
||
343 | $obj = $this->liveOptionObject(); |
||
344 | if (is_object($obj)) { |
||
345 | $v = $obj->Name; |
||
346 | if ($obj->ExplanationPageID) { |
||
347 | $page = $obj->ExplanationPage(); |
||
348 | if ($page) { |
||
349 | $v .= '<div id="PickUpOrDeliveryModifierExplanationLink"><a href="'.$page->Link().'" class="externalLink">'.convert::raw2sql($page->Title).'</a></div>'; |
||
350 | } |
||
351 | } |
||
352 | return $v; |
||
353 | } |
||
354 | return _t("PickUpOrDeliveryModifier.POSTAGEANDHANDLING", "Postage and Handling"); |
||
355 | } |
||
356 | |||
357 | /** |
||
358 | * cached in Order, no need to cache here. |
||
359 | * @return Double |
||
360 | */ |
||
361 | protected function LiveSubTotalAmount() |
||
362 | { |
||
363 | $order = $this->Order(); |
||
364 | return $order->SubTotal(); |
||
365 | } |
||
366 | |||
367 | /** |
||
368 | * description of region and country being shipped to. |
||
369 | * @return PickUpOrDeliveryModifierOptions | NULL |
||
0 ignored issues
–
show
|
|||
370 | */ |
||
371 | protected function LiveSerializedCalculationObject() |
||
372 | { |
||
373 | $obj = $this->liveOptionObject(); |
||
374 | if ($obj) { |
||
375 | return serialize($obj); |
||
376 | } |
||
377 | } |
||
378 | |||
379 | /** |
||
380 | * description of region and country being shipped to. |
||
381 | * @return String |
||
0 ignored issues
–
show
|
|||
382 | */ |
||
383 | protected function LiveRegionAndCountry() |
||
384 | { |
||
385 | $details = array(); |
||
386 | $option = $this->Option(); |
||
0 ignored issues
–
show
|
|||
387 | if ($option) { |
||
388 | $regionID = EcommerceRegion::get_region_id(); |
||
389 | if ($regionID) { |
||
390 | $region = EcommerceRegion::get()->byID($regionID); |
||
391 | if ($region) { |
||
392 | $details[] = $region->Name; |
||
393 | } |
||
394 | } |
||
395 | $countryID = EcommerceCountry::get_country_id(); |
||
396 | if ($countryID) { |
||
397 | $country = EcommerceCountry::get()->byID($countryID); |
||
398 | if ($country) { |
||
399 | $details[] = $country->Name; |
||
400 | } |
||
401 | } |
||
402 | } else { |
||
403 | return _t("PickUpOrDeliveryModifier.NOTSELECTED", "No delivery option has been selected"); |
||
404 | } |
||
405 | if (count($details)) { |
||
406 | return implode(", ", $details); |
||
407 | } |
||
408 | } |
||
409 | |||
410 | /** |
||
411 | * @return Double |
||
412 | **/ |
||
413 | protected function LiveCalculatedTotal() |
||
414 | { |
||
415 | //________________ start caching mechanism |
||
416 | if (self::$calculations_done) { |
||
417 | return self::$_actual_charges; |
||
418 | } |
||
419 | self::$calculations_done = true; |
||
420 | //________________ end caching mechanism |
||
421 | |||
422 | self::$_actual_charges = 0; |
||
0 ignored issues
–
show
The property
$_actual_charges was declared of type double , but 0 is of type integer . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
423 | //do we have enough information |
||
424 | $obj = $this->liveOptionObject(); |
||
425 | $items = $this->Order()->Items(); |
||
426 | if (is_object($obj) && $obj->exists() && $items && $items->count()) { |
||
427 | |||
428 | |||
429 | //are ALL products excluded? |
||
430 | if ($obj->ExcludedProducts() && $obj->ExcludedProducts()->count()) { |
||
431 | $hasIncludedProduct = false; |
||
432 | $excludedProductIDArray = $obj->ExcludedProducts()->column('ID'); |
||
433 | //are all the products excluded? |
||
434 | foreach ($items as $orderItem) { |
||
435 | $product = $orderItem->Product(); |
||
436 | if ($product) { |
||
437 | if (in_array($product->ID, $excludedProductIDArray)) { |
||
0 ignored issues
–
show
This
if statement is empty and can be removed.
This check looks for the bodies of These if (rand(1, 6) > 3) {
//print "Check failed";
} else {
print "Check succeeded";
}
could be turned into if (rand(1, 6) <= 3) {
print "Check succeeded";
}
This is much more concise to read. ![]() |
|||
438 | //do nothing |
||
439 | } else { |
||
440 | $hasIncludedProduct = true; |
||
441 | break; |
||
442 | } |
||
443 | } |
||
444 | } |
||
445 | if ($hasIncludedProduct === false) { |
||
446 | $this->debugMessage .= "<hr />all products are excluded from delivery charges"; |
||
447 | return self::$_actual_charges; |
||
448 | } |
||
449 | } |
||
450 | |||
451 | $this->debugMessage .= "<hr />option selected: ".$obj->Title.", and items present"; |
||
452 | //lets check sub-total |
||
453 | $subTotalAmount = $this->LiveSubTotalAmount(); |
||
454 | $this->debugMessage .= "<hr />sub total amount is: \$". $subTotalAmount; |
||
455 | // no need to charge, order is big enough |
||
456 | $minForZeroRate = floatval($obj->MinimumOrderAmountForZeroRate); |
||
457 | $maxForZeroRate = floatval($obj->FreeShippingUpToThisOrderAmount); |
||
458 | |||
459 | $weigth = $weight = $this->LiveTotalWeight(); |
||
0 ignored issues
–
show
$weigth is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
460 | $weightBrackets = $obj->WeightBrackets(); |
||
461 | $subTotalBrackets = $obj->SubTotalBrackets(); |
||
462 | |||
463 | // zero becauase over minForZeroRate |
||
464 | if ($minForZeroRate > 0 && $minForZeroRate < $subTotalAmount) { |
||
465 | self::$_actual_charges = 0; |
||
466 | $this->debugMessage .= "<hr />Minimum Order Amount For Zero Rate: ".$obj->MinimumOrderAmountForZeroRate." is lower than amount ordered: ".self::$_actual_charges; |
||
467 | } |
||
468 | |||
469 | //zero because below maxForZeroRate |
||
470 | elseif ($maxForZeroRate > 0 && $maxForZeroRate > $subTotalAmount) { |
||
471 | self::$_actual_charges = 0; |
||
472 | $this->debugMessage .= "<hr />Maximum Order Amount For Zero Rate: ".$obj->FreeShippingUpToThisOrderAmount." is higher than amount ordered: ".self::$_actual_charges; |
||
473 | } else { |
||
474 | //examine weight brackets |
||
475 | if ($weight && $weightBrackets->count()) { |
||
476 | $this->debugMessage .= "<hr />there is weight: {$weight}gr."; |
||
477 | //weight brackets |
||
478 | $foundWeightBracket = null; |
||
479 | $weightBracketQuantity = 1; |
||
480 | $additionalWeightBracket = null; |
||
481 | $minimumMinimum = null; |
||
482 | $maximumMaximum = null; |
||
483 | foreach ($weightBrackets as $weightBracket) { |
||
484 | if ((! $foundWeightBracket) && ($weightBracket->MinimumWeight <= $weight) && ($weight <= $weightBracket->MaximumWeight)) { |
||
485 | $foundWeightBracket = $weightBracket; |
||
486 | } |
||
487 | //look for absolute min and max |
||
488 | if ($minimumMinimum === null || ($weightBracket->MinimumWeight > $minimumMinimum->MinimumWeight)) { |
||
489 | $minimumMinimum = $weightBracket; |
||
490 | } |
||
491 | if ($maximumMaximum === null || ($weightBracket->MaximumWeight > $maximumMaximum->MaximumWeight)) { |
||
492 | $maximumMaximum = $weightBracket; |
||
493 | } |
||
494 | } |
||
495 | if (! $foundWeightBracket) { |
||
496 | if ($weight < $minimumMinimum->MinimumWeight) { |
||
497 | $foundWeightBracket = $minimumMinimum; |
||
498 | } elseif ($weight > $maximumMaximum->MaximumWeight) { |
||
499 | $foundWeightBracket = $maximumMaximum; |
||
500 | $weightBracketQuantity = floor($weight / $maximumMaximum->MaximumWeight); |
||
501 | $restWeight = $weight - ($maximumMaximum->MaximumWeight * $weightBracketQuantity); |
||
502 | $additionalWeightBracket = null; |
||
503 | foreach ($weightBrackets as $weightBracket) { |
||
504 | if (($weightBracket->MinimumWeight <= $restWeight) && ($restWeight <= $weightBracket->MaximumWeight)) { |
||
505 | $additionalWeightBracket = $weightBracket; |
||
506 | break; |
||
507 | } |
||
508 | } |
||
509 | } |
||
510 | } |
||
511 | //we found some applicable weight brackets |
||
512 | if ($foundWeightBracket) { |
||
513 | self::$_actual_charges += $foundWeightBracket->FixedCost * $weightBracketQuantity; |
||
514 | $this->debugMessage .= "<hr />found Weight Bracket (from {$foundWeightBracket->MinimumWeight}gr. to {$foundWeightBracket->MaximumWeight}gr.): \${$foundWeightBracket->FixedCost} ({$foundWeightBracket->Name}) from times $weightBracketQuantity"; |
||
515 | if ($additionalWeightBracket) { |
||
516 | self::$_actual_charges += $additionalWeightBracket->FixedCost; |
||
517 | $this->debugMessage .= "<hr />+ additional Weight Bracket (from {$additionalWeightBracket->MinimumWeight}gr. to {$additionalWeightBracket->MaximumWeight}gr.): \${$additionalWeightBracket->FixedCost} ({$foundWeightBracket->Name})"; |
||
518 | } |
||
519 | } |
||
520 | } |
||
521 | |||
522 | |||
523 | |||
524 | // weight based on multiplier ... |
||
525 | elseif ($weight && $obj->WeightMultiplier) { |
||
526 | // add weight based shipping |
||
527 | if (!$obj->WeightUnit) { |
||
528 | $obj->WeightUnit = 1; |
||
529 | } |
||
530 | $this->debugMessage .= "<hr />actual weight:".$weight." multiplier = ".$obj->WeightMultiplier." weight unit = ".$obj->WeightUnit." "; |
||
531 | //legacy fix |
||
532 | $units = ceil($weight / $obj->WeightUnit); |
||
533 | $weightCharge = $units * $obj->WeightMultiplier; |
||
534 | self::$_actual_charges += $weightCharge; |
||
535 | $this->debugMessage .= "<hr />weight charge: ".$weightCharge; |
||
536 | } |
||
537 | |||
538 | |||
539 | //examine price brackets |
||
540 | elseif ($subTotalAmount && $subTotalBrackets->count()) { |
||
541 | $this->debugMessage .= "<hr />there is subTotal: {$subTotalAmount} and subtotal brackets."; |
||
542 | //subTotal brackets |
||
543 | $foundSubTotalBracket = null; |
||
544 | foreach ($subTotalBrackets as $subTotalBracket) { |
||
545 | if ((! $foundSubTotalBracket) && ($subTotalBracket->MinimumSubTotal <= $subTotalAmount) && ($subTotalAmount <= $subTotalBracket->MaximumSubTotal)) { |
||
546 | $foundSubTotalBracket = $subTotalBracket; |
||
547 | break; |
||
548 | } |
||
549 | } |
||
550 | //we found some applicable subTotal brackets |
||
551 | if ($foundSubTotalBracket) { |
||
552 | self::$_actual_charges += $foundSubTotalBracket->FixedCost; |
||
553 | $this->debugMessage .= "<hr />found SubTotal Bracket (between {$foundSubTotalBracket->MinimumSubTotal} and {$foundSubTotalBracket->MaximumSubTotal}): \${$foundSubTotalBracket->FixedCost} ({$foundSubTotalBracket->Name}) "; |
||
554 | } |
||
555 | } |
||
556 | |||
557 | // add percentage |
||
558 | if ($obj->Percentage) { |
||
559 | $percentageCharge = $subTotalAmount * $obj->Percentage; |
||
560 | self::$_actual_charges += $percentageCharge; |
||
561 | $this->debugMessage .= "<hr />percentage charge: \$".$percentageCharge; |
||
562 | } |
||
563 | |||
564 | // add fixed price |
||
565 | if ($obj->FixedCost <> 0) { |
||
566 | self::$_actual_charges += $obj->FixedCost; |
||
567 | $this->debugMessage .= "<hr />fixed charge: \$". $obj->FixedCost; |
||
568 | } |
||
569 | } |
||
570 | //is it enough? |
||
571 | if (self::$_actual_charges < $obj->MinimumDeliveryCharge && $obj->MinimumDeliveryCharge > 0) { |
||
572 | $oldActualCharge = self::$_actual_charges; |
||
573 | self::$_actual_charges = $obj->MinimumDeliveryCharge; |
||
574 | $this->debugMessage .= "<hr />too little: actual charge: ".$oldActualCharge.", minimum delivery charge: ".$obj->MinimumDeliveryCharge; |
||
575 | } |
||
576 | // is it too much |
||
577 | if (self::$_actual_charges > $obj->MaximumDeliveryCharge && $obj->MaximumDeliveryCharge > 0) { |
||
578 | self::$_actual_charges = $obj->MaximumDeliveryCharge; |
||
579 | $this->debugMessage .= "<hr />too much: ".self::$_actual_charges.", maximum delivery charge is ".$obj->MaximumDeliveryCharge; |
||
580 | } |
||
581 | } else { |
||
582 | if (!$items) { |
||
583 | $this->debugMessage .= "<hr />no items present"; |
||
584 | } else { |
||
585 | $this->debugMessage .= "<hr />no delivery option available"; |
||
586 | } |
||
587 | } |
||
588 | $this->debugMessage .= "<hr />final score: \$".self::$_actual_charges; |
||
589 | //special case, we are using weight and there is no weight! |
||
590 | return self::$_actual_charges; |
||
591 | } |
||
592 | |||
593 | /** |
||
594 | * |
||
595 | * |
||
596 | * @return Double |
||
0 ignored issues
–
show
|
|||
597 | */ |
||
598 | protected function LiveTotalWeight() |
||
599 | { |
||
600 | if (self::$_total_weight === null) { |
||
601 | self::$_total_weight = 0; |
||
0 ignored issues
–
show
The property
$_total_weight was declared of type double , but 0 is of type integer . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
602 | if ($this->useWeight()) { |
||
603 | if ($fieldName = Config::inst()->get('PickUpOrDeliveryModifier', 'weight_field')) { |
||
604 | $items = $this->Order()->Items(); |
||
605 | //get index numbers for bonus products - this can only be done now once they have actually been added |
||
606 | if ($items && $items->count()) { |
||
607 | foreach ($items as $itemIndex => $item) { |
||
608 | $buyable = $item->Buyable(); |
||
609 | if ($buyable) { |
||
610 | // Calculate the total weight of the order |
||
611 | if (! empty($buyable->$fieldName) && $item->Quantity) { |
||
612 | self::$_total_weight += $buyable->$fieldName * $item->Quantity; |
||
613 | } |
||
614 | } |
||
615 | } |
||
616 | } |
||
617 | } |
||
618 | } |
||
619 | } |
||
620 | return self::$_total_weight; |
||
621 | } |
||
622 | |||
623 | /** |
||
624 | * returns an explanation of cost. |
||
625 | * @return String |
||
626 | */ |
||
627 | protected function LiveDebugString() |
||
628 | { |
||
629 | return $this->debugMessage; |
||
630 | } |
||
631 | |||
632 | |||
633 | // ######################################## *** Type Functions (IsChargeable, IsDeductable, IsNoChange, IsRemoved) |
||
634 | |||
635 | public function IsChargeable() |
||
636 | { |
||
637 | return true; |
||
638 | } |
||
639 | |||
640 | // ######################################## *** standard database related functions (e.g. onBeforeWrite, onAfterWrite, etc...) |
||
641 | |||
642 | public function requireDefaultRecords() |
||
643 | { |
||
644 | parent::requireDefaultRecords(); |
||
645 | // we must check for individual database types here because each deals with schema in a none standard way |
||
646 | $modifiers = PickUpOrDeliveryModifier::get()->filter(array("OptionID" => 0)); |
||
647 | if ($modifiers->count()) { |
||
648 | DB::alteration_message("You need to upgrade PickUpOrDeliveryModifier <a href=\"/dev/tasks/EcommerceTaskUpgradePickUpOrDeliveryModifier\">do it now!</a>", "deleted"); |
||
649 | } |
||
650 | } |
||
651 | // ######################################## *** AJAX related functions |
||
652 | /** |
||
653 | * |
||
654 | * @param Array $js javascript array |
||
655 | * @return Array for AJAX JSON |
||
656 | **/ |
||
657 | public function updateForAjax(array $js) |
||
658 | { |
||
659 | $js = parent::updateForAjax($js); |
||
660 | $jsonOptions = array(); |
||
661 | $liveOptions = $this->LiveOptions(); |
||
662 | if ($liveOptions && $liveOptions->count()) { |
||
663 | $optionsArray = $liveOptions->map('ID', 'Name'); |
||
664 | if ($optionsArray && !is_array($optionsArray)) { |
||
665 | $optionsArray = $optionsArray->toArray(); |
||
666 | } |
||
667 | if ($optionsArray && count($optionsArray)) { |
||
668 | foreach ($optionsArray as $id => $name) { |
||
669 | $jsonOptions[] = array('id' => $id, 'name' => $name); |
||
670 | } |
||
671 | } |
||
672 | } |
||
673 | $js[] = array( |
||
674 | 't' => 'dropdown', |
||
675 | 's' => 'PickupOrDeliveryType', |
||
676 | 'p' => $this->LiveOptionID(), |
||
677 | 'v' => $jsonOptions |
||
678 | ); |
||
679 | return $js; |
||
680 | } |
||
681 | |||
682 | // ######################################## *** debug functions |
||
683 | } |
||
684 |
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.