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 | * This is a standard Product page-type with fields like |
||
4 | * Price, Weight, Model and basic management of |
||
5 | * groups. |
||
6 | * |
||
7 | * It also has an associated Product_OrderItem class, |
||
8 | * an extension of OrderItem, which is the mechanism |
||
9 | * that links this page type class to the rest of the |
||
10 | * eCommerce platform. This means you can add an instance |
||
11 | * of this page type to the shopping cart. |
||
12 | * |
||
13 | * |
||
14 | * @authors: Nicolaas [at] Sunny Side Up .co.nz |
||
15 | * @package: ecommerce |
||
16 | * @sub-package: buyables |
||
17 | * @inspiration: Silverstripe Ltd, Jeremy |
||
18 | * @todo: Ask the silverstripe gods why $default_sort won't work with FullSiteTreeSort |
||
19 | **/ |
||
20 | class Product extends Page implements BuyableModel |
||
21 | { |
||
22 | /** |
||
23 | * Standard SS variable. |
||
24 | */ |
||
25 | private static $api_access = array( |
||
26 | 'view' => array( |
||
27 | 'Title', |
||
28 | 'Price', |
||
29 | 'Weight', |
||
30 | 'Model', |
||
31 | 'Quantifier', |
||
32 | 'FeaturedProduct', |
||
33 | 'AllowPurchase', |
||
34 | 'InternalItemID', //ie SKU, ProductID etc (internal / existing recognition of product) |
||
35 | 'NumberSold', //store number sold, so it doesn't have to be computed on the fly. Used for determining popularity. |
||
36 | 'Version', |
||
37 | ), |
||
38 | ); |
||
39 | |||
40 | /** |
||
41 | * Standard SS variable. |
||
42 | */ |
||
43 | private static $db = array( |
||
44 | 'Price' => 'Currency', |
||
45 | 'Weight' => 'Float', |
||
46 | 'Model' => 'Varchar(30)', |
||
47 | 'Quantifier' => 'Varchar(30)', |
||
48 | 'FeaturedProduct' => 'Boolean', |
||
49 | 'AllowPurchase' => 'Boolean', |
||
50 | 'InternalItemID' => 'Varchar(30)', //ie SKU, ProductID etc (internal / existing recognition of product) |
||
51 | 'NumberSold' => 'Int', //store number sold, so it doesn't have to be computed on the fly. Used for determining popularity. |
||
52 | 'FullSiteTreeSort' => 'Decimal(64, 0)', //store the complete sort numbers from current page up to level 1 page, for sitetree sorting |
||
53 | 'FullName' => 'Varchar(255)', //Name for look-up lists |
||
54 | 'ShortDescription' => 'Varchar(255)', //For use in lists. |
||
55 | ); |
||
56 | |||
57 | /** |
||
58 | * Standard SS variable. |
||
59 | */ |
||
60 | private static $has_one = array( |
||
61 | 'Image' => 'Product_Image', |
||
62 | ); |
||
63 | |||
64 | /** |
||
65 | * Standard SS variable. |
||
66 | */ |
||
67 | private static $many_many = array( |
||
68 | 'ProductGroups' => 'ProductGroup', |
||
69 | 'AdditionalImages' => 'Image', |
||
70 | 'AdditionalFiles' => 'File', |
||
71 | ); |
||
72 | |||
73 | /** |
||
74 | * Standard SS variable. |
||
75 | */ |
||
76 | private static $casting = array( |
||
77 | 'CalculatedPrice' => 'Currency', |
||
78 | 'CalculatedPriceAsMoney' => 'Money', |
||
79 | 'AllowPurchaseNice' => 'Varchar', |
||
80 | ); |
||
81 | |||
82 | /** |
||
83 | * Standard SS variable. |
||
84 | */ |
||
85 | private static $indexes = array( |
||
86 | 'FullSiteTreeSort' => true, |
||
87 | 'FullName' => true, |
||
88 | 'InternalItemID' => true, |
||
89 | ); |
||
90 | |||
91 | /** |
||
92 | * Standard SS variable. |
||
93 | */ |
||
94 | private static $defaults = array( |
||
95 | 'AllowPurchase' => 1, |
||
96 | ); |
||
97 | |||
98 | /** |
||
99 | * Standard SS variable. |
||
100 | */ |
||
101 | //private static $default_sort = "\"FullSiteTreeSort\" ASC, \"Sort\" ASC, \"InternalItemID\" ASC, \"Price\" ASC"; |
||
102 | //private static $default_sort = "\"Sort\" ASC, \"InternalItemID\" ASC, \"Price\" ASC"; |
||
103 | |||
104 | /** |
||
105 | * Standard SS variable. |
||
106 | */ |
||
107 | private static $summary_fields = array( |
||
108 | 'Image.CMSThumbnail' => 'Image', |
||
109 | 'FullName' => 'Description', |
||
110 | 'Price' => 'Price', |
||
111 | 'AllowPurchaseNice' => 'For Sale', |
||
112 | ); |
||
113 | |||
114 | /** |
||
115 | * Standard SS variable. |
||
116 | */ |
||
117 | private static $searchable_fields = array( |
||
118 | 'FullName' => array( |
||
119 | 'title' => 'Keyword', |
||
120 | 'field' => 'TextField', |
||
121 | ), |
||
122 | 'Price' => array( |
||
123 | 'title' => 'Price', |
||
124 | 'field' => 'NumericField', |
||
125 | ), |
||
126 | 'InternalItemID' => array( |
||
127 | 'title' => 'Internal Item ID', |
||
128 | 'filter' => 'PartialMatchFilter', |
||
129 | ), |
||
130 | 'AllowPurchase', |
||
131 | 'ShowInSearch', |
||
132 | 'ShowInMenus', |
||
133 | 'FeaturedProduct', |
||
134 | ); |
||
135 | |||
136 | /** |
||
137 | * By default we search for products that are allowed to be purchased only |
||
138 | * standard SS method. |
||
139 | * |
||
140 | * @return FieldList |
||
141 | */ |
||
142 | public function scaffoldSearchFields($_params = null) |
||
143 | { |
||
144 | $fields = parent::scaffoldSearchFields($_params); |
||
145 | $fields->fieldByName('AllowPurchase')->setValue(1); |
||
146 | |||
147 | return $fields; |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * Standard SS variable. |
||
152 | */ |
||
153 | private static $singular_name = 'Product'; |
||
154 | public function i18n_singular_name() |
||
155 | { |
||
156 | return _t('Order.PRODUCT', 'Product'); |
||
157 | } |
||
158 | |||
159 | /** |
||
160 | * Standard SS variable. |
||
161 | */ |
||
162 | private static $plural_name = 'Products'; |
||
163 | public function i18n_plural_name() |
||
164 | { |
||
165 | return _t('Order.PRODUCTS', 'Products'); |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * Standard SS variable. |
||
170 | * |
||
171 | * @var string |
||
172 | */ |
||
173 | private static $description = 'A product that is for sale in the shop.'; |
||
174 | |||
175 | /** |
||
176 | * Standard SS variable. |
||
177 | */ |
||
178 | private static $default_parent = 'ProductGroup'; |
||
179 | |||
180 | /** |
||
181 | * Standard SS variable. |
||
182 | */ |
||
183 | private static $icon = 'ecommerce/images/icons/product'; |
||
184 | |||
185 | /** |
||
186 | * Standard SS Method. |
||
187 | */ |
||
188 | public function getCMSFields() |
||
0 ignored issues
–
show
|
|||
189 | { |
||
190 | //prevent calling updateSettingsFields extend function too early |
||
191 | //$siteTreeFieldExtensions = $this->get_static('SiteTree','runCMSFieldsExtensions'); |
||
192 | //$this->disableCMSFieldsExtensions(); |
||
193 | $fields = parent::getCMSFields(); |
||
194 | if ($this->Config()->get('add_data_to_meta_description_for_search')) { |
||
195 | $fields->removeByName('MetaDescription'); |
||
196 | } |
||
197 | //if($siteTreeFieldExtensions) { |
||
198 | //$this->enableCMSFieldsExtensions(); |
||
199 | //} |
||
200 | $fields->replaceField('Root.Main', $htmlEditorField = new HTMLEditorField('Content', _t('Product.DESCRIPTION', 'Product Description'))); |
||
201 | $htmlEditorField->setRows(3); |
||
202 | $fields->addFieldToTab('Root.Main', new TextField('ShortDescription', _t('Product.SHORT_DESCRIPTION', 'Short Description')), 'Content'); |
||
203 | //dirty hack to show images! |
||
204 | $fields->addFieldToTab('Root.Images', $uploadField = new Product_ProductImageUploadField('Image', _t('Product.IMAGE', 'Product Image'))); |
||
205 | $uploadField->setCallingClass('Product'); |
||
206 | $fields->addFieldToTab('Root.Images', $this->getAdditionalImagesField()); |
||
207 | $fields->addFieldToTab('Root.Images', $this->getAdditionalImagesMessage()); |
||
208 | $fields->addFieldToTab('Root.Images', $this->getAdditionalFilesField()); |
||
209 | $fields->addFieldToTab('Root.Details', new ReadonlyField('FullName', _t('Product.FULLNAME', 'Full Name'))); |
||
210 | $fields->addFieldToTab('Root.Details', new ReadOnlyField('FullSiteTreeSort', _t('Product.FULLSITETREESORT', 'Full sort index'))); |
||
211 | $fields->addFieldToTab('Root.Details', $allowPurchaseField = new CheckboxField('AllowPurchase', _t('Product.ALLOWPURCHASE', 'Allow product to be purchased'))); |
||
212 | $config = $this->EcomConfig(); |
||
213 | if ($config && !$config->AllowFreeProductPurchase) { |
||
0 ignored issues
–
show
The property
AllowFreeProductPurchase does not exist on object<EcommerceDBConfig> . 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. ![]() |
|||
214 | $price = $this->getCalculatedPrice(); |
||
215 | if ($price == 0) { |
||
216 | $link = $config->CMSEditLink(); |
||
217 | $allowPurchaseField->setDescription( |
||
218 | _t( |
||
219 | 'Product.DO_NOT_ALLOW_FREE_PRODUCTS_TO_BE_PURCHASED', |
||
220 | "NB: Allow Purchase + zero price is not allowed. Change the <a href=\"$link\">Shop Settings</a> to allow a zero price product purchases or set price on this product." |
||
221 | ) |
||
222 | ); |
||
223 | } |
||
224 | } |
||
225 | |||
226 | $fields->addFieldToTab('Root.Details', new CheckboxField('FeaturedProduct', _t('Product.FEATURED', 'Featured Product'))); |
||
227 | $fields->addFieldToTab('Root.Details', new NumericField('Price', _t('Product.PRICE', 'Price'), '', 12)); |
||
228 | $fields->addFieldToTab('Root.Details', new TextField('InternalItemID', _t('Product.CODE', 'Product Code'), '', 30)); |
||
229 | if ($this->EcomConfig()->ProductsHaveWeight) { |
||
0 ignored issues
–
show
The property
ProductsHaveWeight does not exist on object<EcommerceDBConfig> . 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. ![]() |
|||
230 | $fields->addFieldToTab('Root.Details', new NumericField('Weight', _t('Product.WEIGHT', 'Weight'))); |
||
231 | } |
||
232 | if ($this->EcomConfig()->ProductsHaveModelNames) { |
||
0 ignored issues
–
show
The property
ProductsHaveModelNames does not exist on object<EcommerceDBConfig> . 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. ![]() |
|||
233 | $fields->addFieldToTab('Root.Details', new TextField('Model', _t('Product.MODEL', 'Model'))); |
||
234 | } |
||
235 | if ($this->EcomConfig()->ProductsHaveQuantifiers) { |
||
0 ignored issues
–
show
The property
ProductsHaveQuantifiers does not exist on object<EcommerceDBConfig> . 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. ![]() |
|||
236 | $fields->addFieldToTab( |
||
237 | 'Root.Details', |
||
238 | TextField::create('Quantifier', _t('Product.QUANTIFIER', 'Quantifier')) |
||
239 | ->setRightTitle(_t('Product.QUANTIFIER_EXPLANATION', 'e.g. per kilo, per month, per dozen, each')) |
||
240 | ); |
||
241 | } |
||
242 | if ($this->canPurchase()) { |
||
243 | $fields->addFieldToTab( |
||
244 | 'Root.Main', |
||
245 | new LiteralField( |
||
246 | 'AddToCartLink', |
||
247 | '<p class="message good"><a href="'.$this->AddLink().'">'._t('Product.ADD_TO_CART', 'add to cart').'</a></p>' |
||
248 | ) |
||
249 | ); |
||
250 | } else { |
||
251 | $fields->addFieldToTab( |
||
252 | 'Root.Main', |
||
253 | new LiteralField( |
||
254 | 'AddToCartLink', |
||
255 | '<p class="message warning">'._t('Product.CAN_NOT_BE_ADDED_TO_CART', 'this product can not be added to cart').'</p>' |
||
256 | ) |
||
257 | ); |
||
258 | } |
||
259 | if ($this->EcomConfig()->ProductsAlsoInOtherGroups) { |
||
0 ignored issues
–
show
The property
ProductsAlsoInOtherGroups does not exist on object<EcommerceDBConfig> . 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. ![]() |
|||
260 | $fields->addFieldsToTab( |
||
261 | 'Root.AlsoShowHere', |
||
262 | array( |
||
263 | new HeaderField('ProductGroupsHeader', _t('Product.ALSOSHOWSIN', 'Also shows in ...')), |
||
264 | $this->getProductGroupsTableField(), |
||
265 | ) |
||
266 | ); |
||
267 | } |
||
268 | //if($siteTreeFieldExtensions) { |
||
269 | //$this->extend('updateSettingsFields', $fields); |
||
270 | //} |
||
271 | return $fields; |
||
272 | } |
||
273 | |||
274 | /** |
||
275 | * Used in getCSMFields. |
||
276 | * |
||
277 | * @return GridField |
||
278 | **/ |
||
279 | protected function getProductGroupsTableField() |
||
280 | { |
||
281 | $gridField = new GridField( |
||
282 | 'ProductGroups', |
||
283 | _t('Product.THIS_PRODUCT_SHOULD_ALSO_BE_LISTED_UNDER', 'This product is also listed under ...'), |
||
284 | $this->ProductGroups(), |
||
285 | GridFieldBasicPageRelationConfig::create() |
||
286 | ); |
||
287 | |||
288 | return $gridField; |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * Used in getCSMFields. |
||
293 | * |
||
294 | * @return LiteralField |
||
295 | **/ |
||
296 | protected function getAdditionalImagesMessage() |
||
297 | { |
||
298 | $msg = ''; |
||
299 | if ($this->InternalItemID) { |
||
300 | $findImagesTask = EcommerceTaskLinkProductWithImages::create(); |
||
301 | $findImagesLink = $findImagesTask->Link(); |
||
302 | $findImagesLinkOne = $findImagesLink.'?productid='.$this->ID; |
||
303 | $msg .= ' |
||
304 | <h3>Batch Upload</h3> |
||
305 | <p> |
||
306 | To batch upload additional images and files, please go to the <a href="/admin/assets">Files section</a>, and upload them there. |
||
307 | Files need to be named in the following way: |
||
308 | An additional image for your product should be named <Product Code>_(00 to 99).(png/jpg/gif). <br />For example, you may name your image: |
||
309 | <strong>'.$this->InternalItemID."_08.jpg</strong>. |
||
310 | <br /><br />You can <a href=\"$findImagesLinkOne\" target='_blank'>find images for <i>".$this->Title."</i></a> or |
||
311 | <a href=\"$findImagesLink\" target='_blank'>images for all products</a> ... |
||
312 | </p>"; |
||
313 | } else { |
||
314 | $msg .= ' |
||
315 | <h3>Batch Upload</h3> |
||
316 | <p>To batch upload additional images and files, you must first specify a product code.</p>'; |
||
317 | } |
||
318 | $field = new LiteralField('ImageFileNote', $msg); |
||
319 | |||
320 | return $field; |
||
321 | } |
||
322 | |||
323 | /** |
||
324 | * Used in getCSMFields. |
||
325 | * |
||
326 | * @return GridField |
||
0 ignored issues
–
show
|
|||
327 | **/ |
||
328 | protected function getAdditionalImagesField() |
||
329 | { |
||
330 | $uploadField = new UploadFIeld( |
||
331 | 'AdditionalImages', |
||
332 | 'More images' |
||
333 | ); |
||
334 | $uploadField->setAllowedMaxFileNumber(12); |
||
335 | return $uploadField; |
||
336 | } |
||
337 | |||
338 | /** |
||
339 | * Used in getCSMFields. |
||
340 | * |
||
341 | * @return GridField |
||
0 ignored issues
–
show
|
|||
342 | **/ |
||
343 | protected function getAdditionalFilesField() |
||
344 | { |
||
345 | $uploadField = new UploadFIeld( |
||
346 | 'AdditionalFiles', |
||
347 | 'Additional Files' |
||
348 | ); |
||
349 | $uploadField->setAllowedMaxFileNumber(12); |
||
350 | return $uploadField; |
||
351 | } |
||
352 | |||
353 | /** |
||
354 | * How to view using AJAX |
||
355 | * e.g. if you want to load the produyct in a list - using AJAX |
||
356 | * then use this link |
||
357 | * Opening the link will return a HTML snippet. |
||
358 | * |
||
359 | * @return string |
||
360 | */ |
||
361 | public function AjaxLink() |
||
362 | { |
||
363 | return $this->Link('ajaxview'); |
||
364 | } |
||
365 | |||
366 | /** |
||
367 | * Adds keywords to the MetaKeyword |
||
368 | * Standard SS Method. |
||
369 | */ |
||
370 | public function onBeforeWrite() |
||
371 | { |
||
372 | parent::onBeforeWrite(); |
||
373 | $config = $this->EcomConfig(); |
||
0 ignored issues
–
show
$config 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 ![]() |
|||
374 | //set allowpurchase to false IF |
||
375 | //free products are not allowed to be purchased |
||
376 | |||
377 | $filter = EcommerceCodeFilter::create(); |
||
378 | $filter->checkCode($this, 'InternalItemID'); |
||
379 | $this->prepareFullFields(); |
||
380 | //we are adding all the fields to the keyword fields here for searching purposes. |
||
381 | //because the MetaKeywords Field is being searched. |
||
382 | if ($this->Config()->get('add_data_to_meta_description_for_search')) { |
||
383 | $this->MetaDescription = ''; |
||
384 | $fieldsToExclude = Config::inst()->get('SiteTree', 'db'); |
||
385 | foreach ($this->db() as $fieldName => $fieldType) { |
||
386 | if (is_string($this->$fieldName) && strlen($this->$fieldName) > 2) { |
||
387 | if (!in_array($fieldName, $fieldsToExclude)) { |
||
388 | $this->MetaDescription .= strip_tags($this->$fieldName); |
||
389 | } |
||
390 | } |
||
391 | } |
||
392 | if ($this->hasExtension('ProductWithVariationDecorator')) { |
||
393 | $variations = $this->Variations(); |
||
394 | if ($variations) { |
||
395 | $variationCount = $variations->count(); |
||
396 | if ($variationCount > 0 && $variationCount < 8) { |
||
397 | foreach ($variations as $variation) { |
||
398 | $this->MetaDescription .= ' - '.$variation->FullName; |
||
399 | } |
||
400 | } |
||
401 | } |
||
402 | } |
||
403 | } |
||
404 | } |
||
405 | |||
406 | /** |
||
407 | * standard SS Method |
||
408 | * Make sure that the image is a product image. |
||
409 | */ |
||
410 | public function onAfterWrite() |
||
411 | { |
||
412 | parent::onAfterWrite(); |
||
413 | if ($this->ImageID) { |
||
414 | if ($normalImage = Image::get()->exclude(array('ClassName' => 'Product_Image'))->byID($this->ImageID)) { |
||
415 | $normalImage = $normalImage->newClassInstance('Product_Image'); |
||
416 | $normalImage->write(); |
||
417 | } |
||
418 | } |
||
419 | } |
||
420 | |||
421 | |||
422 | /** |
||
423 | * sets the FullName and FullSiteTreeField to the latest values |
||
424 | * This can be useful as you can compare it to the ones saved in the database. |
||
425 | * Returns true if the value is different from the one in the database. |
||
426 | * |
||
427 | * @return bool |
||
428 | */ |
||
429 | public function prepareFullFields() |
||
430 | { |
||
431 | //FullName |
||
432 | $fullName = ''; |
||
433 | if ($this->InternalItemID) { |
||
434 | $fullName .= $this->InternalItemID.': '; |
||
435 | } |
||
436 | $fullName .= $this->Title; |
||
437 | //FullSiteTreeSort |
||
438 | $parentSortArray = array(sprintf('%03d', $this->Sort)); |
||
439 | $obj = $this; |
||
440 | $parentTitleArray = array(); |
||
441 | while ($obj && $obj->ParentID) { |
||
442 | $obj = SiteTree::get()->byID(intval($obj->ParentID) - 0); |
||
443 | if ($obj) { |
||
444 | $parentSortArray[] = sprintf('%03d', $obj->Sort); |
||
445 | if (is_a($obj, Object::getCustomClass('ProductGroup'))) { |
||
446 | $parentTitleArray[] = $obj->Title; |
||
447 | } |
||
448 | } |
||
449 | } |
||
450 | $reverseArray = array_reverse($parentSortArray); |
||
451 | $parentTitle = ''; |
||
452 | if (count($parentTitleArray)) { |
||
453 | $parentTitle = ' ('._t('product.IN', 'in').' '.implode(' / ', $parentTitleArray).')'; |
||
454 | } |
||
455 | //setting fields with new values! |
||
456 | $this->FullName = $fullName.$parentTitle; |
||
457 | $this->FullSiteTreeSort = implode('', array_map($this->numberPad, $reverseArray)); |
||
458 | if (($this->dbObject('FullName') != $this->FullName) || ($this->dbObject('FullSiteTreeSort') != $this->FullSiteTreeSort)) { |
||
0 ignored issues
–
show
|
|||
459 | return true; |
||
460 | } |
||
461 | |||
462 | return false; |
||
463 | } |
||
464 | |||
465 | //GROUPS AND SIBLINGS |
||
466 | |||
467 | /** |
||
468 | * Returns all the parent groups for the product. |
||
469 | * |
||
470 | *@return DataList (ProductGroups) |
||
471 | **/ |
||
472 | public function AllParentGroups() |
||
473 | { |
||
474 | $otherGroupsArray = $this->ProductGroups()->map('ID', 'ID')->toArray(); |
||
475 | |||
476 | return ProductGroup::get()->filter( |
||
477 | array( |
||
478 | 'ID' => array($this->ParentID => $this->ParentID) + $otherGroupsArray, |
||
479 | ) |
||
480 | ); |
||
481 | } |
||
482 | |||
483 | /** |
||
484 | * Returns all the parent groups for the product, |
||
485 | * including the parents and parents and so on. |
||
486 | * |
||
487 | * @return DataList (ProductGroups) |
||
488 | */ |
||
489 | public function AllParentGroupsIncludingParents() |
||
490 | { |
||
491 | $directParents = $this->AllParentGroups(); |
||
492 | $allParentsArray = array(); |
||
493 | foreach ($directParents as $parent) { |
||
494 | $obj = $parent; |
||
495 | $allParentsArray[$obj->ID] = $obj->ID; |
||
496 | while ($obj && $obj->ParentID) { |
||
497 | $obj = SiteTree::get()->byID(intval($obj->ParentID) - 0); |
||
498 | if ($obj) { |
||
499 | if (is_a($obj, Object::getCustomClass('ProductGroup'))) { |
||
500 | $allParentsArray[$obj->ID] = $obj->ID; |
||
501 | } |
||
502 | } |
||
503 | } |
||
504 | } |
||
505 | |||
506 | return ProductGroup::get()->filter(array('ID' => $allParentsArray)); |
||
507 | } |
||
508 | |||
509 | /** |
||
510 | * @return Product ... |
||
511 | * we have this so that Variations can link to products |
||
512 | * and products link to themselves... |
||
513 | */ |
||
514 | public function getProduct() |
||
515 | { |
||
516 | return $this; |
||
517 | } |
||
518 | |||
519 | /** |
||
520 | * Returns the direct parent group for the product. |
||
521 | * |
||
522 | * @return ProductGroup | NULL |
||
523 | **/ |
||
524 | public function MainParentGroup() |
||
525 | { |
||
526 | return ProductGroup::get()->byID($this->ParentID); |
||
527 | } |
||
528 | |||
529 | /** |
||
530 | * Returns the top parent group of the product (in the hierarchy). |
||
531 | * |
||
532 | * @return ProductGroup | NULL |
||
533 | **/ |
||
534 | public function TopParentGroup() |
||
535 | { |
||
536 | $parent = $this->MainParentGroup(); |
||
537 | $x = 0; |
||
538 | while ($parent && $x < 100) { |
||
539 | $returnValue = $parent; |
||
540 | $parent = DataObject::get_one( |
||
541 | 'ProductGroup', |
||
542 | array('ID' => $parent->ParentID) |
||
543 | ); |
||
544 | ++$x; |
||
545 | } |
||
546 | |||
547 | return $returnValue; |
||
0 ignored issues
–
show
The variable
$returnValue 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
![]() |
|||
548 | } |
||
549 | |||
550 | /** |
||
551 | * Returns products in the same group. |
||
552 | * |
||
553 | * @return DataList (Products) |
||
554 | **/ |
||
555 | public function Siblings() |
||
556 | { |
||
557 | if ($this->ParentID) { |
||
558 | $extension = ''; |
||
0 ignored issues
–
show
$extension 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 ![]() |
|||
559 | if (Versioned::current_stage() == 'Live') { |
||
560 | $extension = '_Live'; |
||
0 ignored issues
–
show
$extension 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 ![]() |
|||
561 | } |
||
562 | |||
563 | return Product::get() |
||
564 | ->filter(array( |
||
565 | 'ShowInMenus' => 1, |
||
566 | 'ParentID' => $this->ParentID, |
||
567 | )) |
||
568 | ->exclude(array('ID' => $this->ID)); |
||
569 | } |
||
570 | } |
||
571 | |||
572 | //IMAGE |
||
573 | /** |
||
574 | * returns a "BestAvailable" image if the current one is not available |
||
575 | * In some cases this is appropriate and in some cases this is not. |
||
576 | * For example, consider the following setup |
||
577 | * - product A with three variations |
||
578 | * - Product A has an image, but the variations have no images |
||
579 | * With this scenario, you want to show ONLY the product image |
||
580 | * on the product page, but if one of the variations is added to the |
||
581 | * cart, then you want to show the product image. |
||
582 | * This can be achieved bu using the BestAvailable image. |
||
583 | * |
||
584 | * @return Image | Null |
||
0 ignored issues
–
show
|
|||
585 | */ |
||
586 | public function BestAvailableImage() |
||
587 | { |
||
588 | $product = Product::get()->byID($this->ID); |
||
589 | if ($product && $product->ImageID) { |
||
590 | $image = Image::get()->byID($product->ImageID); |
||
591 | if ($image) { |
||
592 | if (file_exists($image->getFullPath())) { |
||
593 | return $image; |
||
594 | } |
||
595 | } |
||
596 | } |
||
597 | if ($parent = $this->MainParentGroup()) { |
||
598 | return $parent->BestAvailableImage(); |
||
599 | } |
||
600 | } |
||
601 | |||
602 | /** |
||
603 | * Little hack to show thumbnail in summary fields in modeladmin in CMS. |
||
604 | * |
||
605 | * @return string (HTML = formatted image) |
||
606 | */ |
||
607 | public function CMSThumbnail() |
||
608 | { |
||
609 | if ($image = $this->Image()) { |
||
610 | if ($image->exists()) { |
||
611 | return $image->Thumbnail(); |
||
612 | } |
||
613 | } |
||
614 | |||
615 | return '['._t('product.NOIMAGE', 'no image').']'; |
||
616 | } |
||
617 | |||
618 | /** |
||
619 | * Returns a link to a default image. |
||
620 | * If a default image is set in the site config then this link is returned |
||
621 | * Otherwise, a standard link is returned. |
||
622 | * |
||
623 | * @return string |
||
624 | */ |
||
625 | public function DefaultImageLink() |
||
626 | { |
||
627 | return $this->EcomConfig()->DefaultImageLink(); |
||
628 | } |
||
629 | |||
630 | /** |
||
631 | * returns the default image of the product. |
||
632 | * |
||
633 | * @return Image | Null |
||
0 ignored issues
–
show
|
|||
634 | */ |
||
635 | public function DefaultImage() |
||
636 | { |
||
637 | return $this->EcomConfig()->DefaultImage(); |
||
638 | } |
||
639 | |||
640 | /** |
||
641 | * returns a product image for use in templates |
||
642 | * e.g. $DummyImage.Width();. |
||
643 | * |
||
644 | * @return Product_Image |
||
645 | */ |
||
646 | public function DummyImage() |
||
647 | { |
||
648 | return new Product_Image(); |
||
649 | } |
||
650 | |||
651 | // VERSIONING |
||
652 | |||
653 | /** |
||
654 | * Conditions for whether a product can be purchased. |
||
655 | * |
||
656 | * If it has the checkbox for 'Allow this product to be purchased', |
||
657 | * as well as having a price, it can be purchased. Otherwise a user |
||
658 | * can't buy it. |
||
659 | * |
||
660 | * Other conditions may be added by decorating with the canPurcahse function |
||
661 | * |
||
662 | * @return bool |
||
663 | */ |
||
664 | |||
665 | /** |
||
666 | * @TODO: complete |
||
667 | * |
||
668 | * @param string $compontent - the has many relationship you are looking at, e.g. OrderAttribute |
||
0 ignored issues
–
show
There is no parameter named
$compontent . Did you maybe mean $component ?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit. Consider the following example. The parameter /**
* @param array $germany
* @param array $ireland
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was changed, but the annotation was not. ![]() |
|||
669 | * |
||
670 | * @return DataList (CHECK!) |
||
671 | */ |
||
672 | public function getVersionedComponents($component = 'ProductVariations') |
||
673 | { |
||
674 | return; |
||
675 | $baseTable = ClassInfo::baseDataClass(self::$has_many[$component]); |
||
0 ignored issues
–
show
$baseTable = \ClassInfo:...$has_many[$component]); does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
676 | $query = singleton(self::$has_many[$component])->buildVersionSQL("\"{$baseTable}\".ProductID = {$this->ID} AND \"{$baseTable}\".Version = {$this->Version}"); |
||
677 | $result = singleton(self::$has_many[$component])->buildDataObjectSet($query->execute()); |
||
678 | |||
679 | return $result; |
||
680 | } |
||
681 | |||
682 | /** |
||
683 | * Action to return specific version of a specific product. |
||
684 | * This can be any product to enable the retrieval of deleted products. |
||
685 | * This is really useful for sold products where you want to retrieve the actual version that you sold. |
||
686 | * If the version can not be found then we retrieve the current one. |
||
687 | * |
||
688 | * @param int $id |
||
689 | * @param int $version |
||
690 | * |
||
691 | * @return DataObject | Null |
||
692 | */ |
||
693 | public function getVersionOfBuyable($id = 0, $version = 0) |
||
694 | { |
||
695 | if (!$id) { |
||
696 | $id = $this->ID; |
||
697 | } |
||
698 | if (!$version) { |
||
699 | $version = $this->Version; |
||
700 | } |
||
701 | //not sure why this is running via OrderItem... |
||
702 | $obj = OrderItem::get_version($this->ClassName, $id, $version); |
||
703 | if (!$obj) { |
||
704 | $className = $this->ClassName; |
||
705 | $obj = $className::get()->byID($id); |
||
706 | } |
||
707 | |||
708 | return $obj; |
||
709 | } |
||
710 | |||
711 | //ORDER ITEM |
||
712 | |||
713 | /** |
||
714 | * returns the order item associated with the buyable. |
||
715 | * ALWAYS returns one, even if there is none in the cart. |
||
716 | * Does not write to database. |
||
717 | * |
||
718 | * @return OrderItem (no kidding) |
||
719 | **/ |
||
720 | public function OrderItem() |
||
721 | { |
||
722 | //work out the filter |
||
723 | $filterArray = array(); |
||
724 | $extendedFilter = $this->extend('updateItemFilter', $filter); |
||
0 ignored issues
–
show
The variable
$filter does not exist. Did you mean $filterArray ?
This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name. The variable may have been renamed without also renaming all references. ![]() |
|||
725 | if ($extendedFilter !== null && is_array($extendedFilter) && count($extendedFilter)) { |
||
726 | $filterArray = $extendedFilter; |
||
727 | } |
||
728 | //make the item and extend |
||
729 | $item = ShoppingCart::singleton()->findOrMakeItem($this, $filterArray); |
||
730 | $this->extend('updateDummyItem', $item); |
||
731 | |||
732 | return $item; |
||
733 | } |
||
734 | |||
735 | /** |
||
736 | * @var string |
||
737 | */ |
||
738 | protected $defaultClassNameForOrderItem = 'Product_OrderItem'; |
||
739 | |||
740 | /** |
||
741 | * you can overwrite this function in your buyable items (such as Product). |
||
742 | * |
||
743 | * @return string |
||
744 | **/ |
||
745 | public function classNameForOrderItem() |
||
746 | { |
||
747 | $className = $this->defaultClassNameForOrderItem; |
||
748 | $updateClassName = $this->extend('updateClassNameForOrderItem', $className); |
||
749 | if ($updateClassName !== null && is_array($updateClassName) && count($updateClassName)) { |
||
750 | $className = $updateClassName[0]; |
||
751 | } |
||
752 | |||
753 | return $className; |
||
754 | } |
||
755 | |||
756 | /** |
||
757 | * You can set an alternative class name for order item using this method. |
||
758 | * |
||
759 | * @param string $ClassName |
||
0 ignored issues
–
show
There is no parameter named
$ClassName . Did you maybe mean $className ?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit. Consider the following example. The parameter /**
* @param array $germany
* @param array $ireland
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was changed, but the annotation was not. ![]() |
|||
760 | **/ |
||
761 | public function setAlternativeClassNameForOrderItem($className) |
||
762 | { |
||
763 | $this->defaultClassNameForOrderItem = $className; |
||
764 | } |
||
765 | |||
766 | /** |
||
767 | * This is used when you add a product to your cart |
||
768 | * if you set it to 1 then you can add 0.1 product to cart. |
||
769 | * If you set it to -1 then you can add 10, 20, 30, etc.. products to cart. |
||
770 | * |
||
771 | * @return int |
||
772 | **/ |
||
773 | public function QuantityDecimals() |
||
774 | { |
||
775 | return 0; |
||
776 | } |
||
777 | |||
778 | /** |
||
779 | * Number of items sold. |
||
780 | * |
||
781 | * @return int |
||
782 | */ |
||
783 | public function HasBeenSold() |
||
784 | { |
||
785 | return $this->getHasBeenSold(); |
||
786 | } |
||
787 | public function getHasBeenSold() |
||
788 | { |
||
789 | $dataList = Order::get_datalist_of_orders_with_submit_record($onlySubmittedOrders = true, $includeCancelledOrders = false); |
||
790 | $dataList = $dataList->innerJoin('OrderAttribute', '"OrderAttribute"."OrderID" = "Order"."ID"'); |
||
791 | $dataList = $dataList->innerJoin('OrderItem', '"OrderAttribute"."ID" = "OrderItem"."ID"'); |
||
792 | $dataList = $dataList->filter( |
||
793 | array( |
||
794 | 'BuyableID' => $this->ID, |
||
795 | 'buyableClassName' => $this->ClassName |
||
796 | ) |
||
797 | ); |
||
798 | |||
799 | return $dataList->count(); |
||
800 | } |
||
801 | |||
802 | //LINKS |
||
803 | |||
804 | /** |
||
805 | * Tells us the link to select variations |
||
806 | * If ajaxified, this controller method (selectvariation) |
||
807 | * Will return a html snippet for selecting the variation. |
||
808 | * This is useful in the Product Group where you can both |
||
809 | * non-variation and variation products to have the same |
||
810 | * "add to cart" button. Using this link you can provide a |
||
811 | * pop-up select system for selecting a variation. |
||
812 | * |
||
813 | * @return string |
||
814 | */ |
||
815 | public function AddVariationsLink() |
||
816 | { |
||
817 | return $this->Link('selectvariation'); |
||
818 | } |
||
819 | |||
820 | /** |
||
821 | * passing on shopping cart links ...is this necessary?? ...why not just pass the cart? |
||
822 | * |
||
823 | * @return string |
||
824 | */ |
||
825 | public function AddLink() |
||
826 | { |
||
827 | return ShoppingCart_Controller::add_item_link($this->ID, $this->ClassName, $this->linkParameters('add')); |
||
828 | } |
||
829 | |||
830 | /** |
||
831 | * link use to add (one) to cart. |
||
832 | * |
||
833 | *@return string |
||
834 | */ |
||
835 | public function IncrementLink() |
||
836 | { |
||
837 | //we can do this, because by default add link adds one |
||
838 | return ShoppingCart_Controller::add_item_link($this->ID, $this->ClassName, $this->linkParameters('increment')); |
||
839 | } |
||
840 | |||
841 | /** |
||
842 | * Link used to remove one from cart |
||
843 | * we can do this, because by default remove link removes one. |
||
844 | * |
||
845 | * @return string |
||
846 | */ |
||
847 | public function DecrementLink() |
||
848 | { |
||
849 | return ShoppingCart_Controller::remove_item_link($this->ID, $this->ClassName, $this->linkParameters('decrement')); |
||
850 | } |
||
851 | |||
852 | /** |
||
853 | * remove one buyable's orderitem from cart. |
||
854 | * |
||
855 | * @return string (Link) |
||
856 | */ |
||
857 | public function RemoveLink() |
||
858 | { |
||
859 | return ShoppingCart_Controller::remove_item_link($this->ID, $this->ClassName, $this->linkParameters('remove')); |
||
860 | } |
||
861 | |||
862 | /** |
||
863 | * remove all of this buyable's orderitem from cart. |
||
864 | * |
||
865 | * @return string (Link) |
||
866 | */ |
||
867 | public function RemoveAllLink() |
||
868 | { |
||
869 | return ShoppingCart_Controller::remove_all_item_link($this->ID, $this->ClassName, $this->linkParameters('removeall')); |
||
870 | } |
||
871 | |||
872 | /** |
||
873 | * remove all of this buyable's orderitem from cart and go through to this buyble to add alternative selection. |
||
874 | * |
||
875 | * @return string (Link) |
||
876 | */ |
||
877 | public function RemoveAllAndEditLink() |
||
878 | { |
||
879 | return ShoppingCart_Controller::remove_all_item_and_edit_link($this->ID, $this->ClassName, $this->linkParameters('removeallandedit')); |
||
880 | } |
||
881 | |||
882 | /** |
||
883 | * set new specific new quantity for buyable's orderitem. |
||
884 | * |
||
885 | * @param float |
||
886 | * |
||
887 | * @return string (Link) |
||
888 | */ |
||
889 | public function SetSpecificQuantityItemLink($quantity) |
||
890 | { |
||
891 | return ShoppingCart_Controller::set_quantity_item_link($this->ID, $this->ClassName, array_merge($this->linkParameters('setspecificquantityitem'), array('quantity' => $quantity))); |
||
892 | } |
||
893 | |||
894 | /** |
||
895 | * @return string |
||
896 | */ |
||
897 | public function AddToCartAndGoToCheckoutLink() |
||
898 | { |
||
899 | $array = $this->linkParameters(); |
||
900 | $array['BackURL'] = urlencode(CheckoutPage::find_link()); |
||
901 | |||
902 | return ShoppingCart_Controller::add_item_link($this->ID, $this->ClassName, $array); |
||
903 | } |
||
904 | |||
905 | /** |
||
906 | * |
||
907 | * |
||
908 | * @return string |
||
909 | */ |
||
910 | public function VersionedLink() |
||
911 | { |
||
912 | return Controller::join_links( |
||
913 | Director::baseURL(), |
||
914 | EcommerceConfig::get('ShoppingCart_Controller', 'url_segment'), |
||
915 | 'submittedbuyable', |
||
916 | $this->ClassName, |
||
917 | $this->ID, |
||
918 | $this->Version |
||
919 | ); |
||
920 | } |
||
921 | |||
922 | public function RemoveFromSaleLink() |
||
923 | { |
||
924 | return ShoppingCart_Controller::remove_from_sale_link($this->ID, $this->ClassName); |
||
925 | } |
||
926 | |||
927 | /** |
||
928 | * Here you can add additional information to your product |
||
929 | * links such as the AddLink and the RemoveLink. |
||
930 | * One useful parameter you can add is the BackURL link. |
||
931 | * |
||
932 | * Usage would be by means of |
||
933 | * 1. decorating product |
||
934 | * 2. adding a updateLinkParameters method |
||
935 | * 3. adding items to the array. |
||
936 | * |
||
937 | * You can also extend Product and override this method... |
||
938 | * |
||
939 | * @return array |
||
940 | **/ |
||
941 | protected function linkParameters($type = '') |
||
942 | { |
||
943 | $array = array(); |
||
944 | $extendedArray = $this->extend('updateLinkParameters', $array, $type); |
||
945 | if ($extendedArray !== null && is_array($extendedArray) && count($extendedArray)) { |
||
946 | foreach ($extendedArray as $extendedArrayUpdate) { |
||
947 | $array = array_merge($array, $extendedArrayUpdate); |
||
948 | } |
||
949 | } |
||
950 | |||
951 | return $array; |
||
952 | } |
||
953 | |||
954 | //TEMPLATE STUFF |
||
955 | |||
956 | /** |
||
957 | * @return bool |
||
958 | */ |
||
959 | public function IsInCart() |
||
960 | { |
||
961 | return ($this->OrderItem() && $this->OrderItem()->Quantity > 0) ? true : false; |
||
0 ignored issues
–
show
The property
Quantity does not exist on object<OrderItem> . 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. ![]() |
|||
962 | } |
||
963 | |||
964 | /** |
||
965 | * @return EcomQuantityField |
||
966 | */ |
||
967 | public function EcomQuantityField() |
||
968 | { |
||
969 | return EcomQuantityField::create($this); |
||
970 | } |
||
971 | |||
972 | /** |
||
973 | * returns the instance of EcommerceConfigAjax for use in templates. |
||
974 | * In templates, it is used like this: |
||
975 | * $EcommerceConfigAjax.TableID. |
||
976 | * |
||
977 | * @return EcommerceConfigAjax |
||
0 ignored issues
–
show
|
|||
978 | **/ |
||
979 | public function AJAXDefinitions() |
||
980 | { |
||
981 | return EcommerceConfigAjax::get_one($this); |
||
982 | } |
||
983 | |||
984 | /** |
||
985 | * @return EcommerceDBConfig |
||
986 | **/ |
||
987 | public function EcomConfig() |
||
988 | { |
||
989 | return EcommerceDBConfig::current_ecommerce_db_config(); |
||
990 | } |
||
991 | |||
992 | /** |
||
993 | * Is it a variation? |
||
994 | * |
||
995 | * @return bool |
||
996 | */ |
||
997 | public function IsProductVariation() |
||
998 | { |
||
999 | return false; |
||
1000 | } |
||
1001 | |||
1002 | /** |
||
1003 | * tells us if the current page is part of e-commerce. |
||
1004 | * |
||
1005 | * @return bool |
||
1006 | */ |
||
1007 | public function IsEcommercePage() |
||
1008 | { |
||
1009 | return true; |
||
1010 | } |
||
1011 | |||
1012 | public function AllowPurchaseNice() |
||
1013 | { |
||
1014 | return $this->obj('AllowPurchase')->Nice(); |
||
1015 | } |
||
1016 | |||
1017 | /** |
||
1018 | * Products have a standard price, but for specific situations they have a calculated price. |
||
1019 | * The Price can be changed for specific member discounts, etc... |
||
1020 | * |
||
1021 | * @return float |
||
1022 | */ |
||
1023 | public function CalculatedPrice() |
||
1024 | { |
||
1025 | return $this->getCalculatedPrice(); |
||
1026 | } |
||
1027 | |||
1028 | private static $_calculated_price_cache = array(); |
||
1029 | |||
1030 | /** |
||
1031 | * Products have a standard price, but for specific situations they have a calculated price. |
||
1032 | * The Price can be changed for specific member discounts, etc... |
||
1033 | * |
||
1034 | * We add three "hooks" / "extensions" here... so that you can update prices |
||
1035 | * in a logical order (e.g. firstly change to forex and then apply discount) |
||
1036 | * |
||
1037 | * @return float |
||
1038 | */ |
||
1039 | public function getCalculatedPrice($forceRecalculation = false) |
||
1040 | { |
||
1041 | if (! isset(self::$_calculated_price_cache[$this->ID]) || $forceRecalculation) { |
||
1042 | $price = $this->Price; |
||
1043 | $updatedPrice = $this->extend('updateBeforeCalculatedPrice', $price); |
||
1044 | if ($updatedPrice !== null && is_array($updatedPrice) && count($updatedPrice)) { |
||
1045 | $price = $updatedPrice[0]; |
||
1046 | } |
||
1047 | $updatedPrice = $this->extend('updateCalculatedPrice', $price); |
||
1048 | if ($updatedPrice !== null && is_array($updatedPrice) && count($updatedPrice)) { |
||
1049 | $price = $updatedPrice[0]; |
||
1050 | } |
||
1051 | $updatedPrice = $this->extend('updateAfterCalculatedPrice', $price); |
||
1052 | if ($updatedPrice !== null && is_array($updatedPrice) && count($updatedPrice)) { |
||
1053 | $price = $updatedPrice[0]; |
||
1054 | } |
||
1055 | self::$_calculated_price_cache[$this->ID] = $price; |
||
1056 | } |
||
1057 | return self::$_calculated_price_cache[$this->ID]; |
||
1058 | } |
||
1059 | |||
1060 | /** |
||
1061 | * How do we display the price? |
||
1062 | * |
||
1063 | * @return Money |
||
1064 | */ |
||
1065 | public function CalculatedPriceAsMoney() |
||
1066 | { |
||
1067 | return $this->getCalculatedPriceAsMoney(); |
||
1068 | } |
||
1069 | public function getCalculatedPriceAsMoney() |
||
1070 | { |
||
1071 | return EcommerceCurrency::get_money_object_from_order_currency($this->getCalculatedPrice()); |
||
1072 | } |
||
1073 | |||
1074 | //CRUD SETTINGS |
||
1075 | |||
1076 | /** |
||
1077 | * Is the product for sale? |
||
1078 | * |
||
1079 | * @param Member $member |
||
0 ignored issues
–
show
Should the type for parameter
$member not be null|Member ?
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. ![]() |
|||
1080 | * @param bool $checkPrice |
||
1081 | * |
||
1082 | * @return bool |
||
1083 | */ |
||
1084 | public function canPurchase(Member $member = null, $checkPrice = true) |
||
1085 | { |
||
1086 | $config = $this->EcomConfig(); |
||
1087 | //shop closed |
||
1088 | if ($config->ShopClosed) { |
||
0 ignored issues
–
show
The property
ShopClosed does not exist on object<EcommerceDBConfig> . 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. ![]() |
|||
1089 | return false; |
||
1090 | } |
||
1091 | //not sold at all |
||
1092 | if (! $this->AllowPurchase) { |
||
1093 | return false; |
||
1094 | } |
||
1095 | //check country |
||
1096 | if (! $member) { |
||
1097 | $member = Member::currentUser(); |
||
1098 | } |
||
1099 | $extended = $this->extendedCan('canPurchaseByCountry', $member); |
||
1100 | if ($extended !== null) { |
||
1101 | return $extended; |
||
1102 | } |
||
1103 | if (! EcommerceCountry::allow_sales()) { |
||
1104 | return false; |
||
1105 | } |
||
1106 | |||
1107 | if ($checkPrice) { |
||
1108 | $price = $this->getCalculatedPrice(); |
||
1109 | if ($price == 0 && !$config->AllowFreeProductPurchase) { |
||
0 ignored issues
–
show
The property
AllowFreeProductPurchase does not exist on object<EcommerceDBConfig> . 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. ![]() |
|||
1110 | return false; |
||
1111 | } |
||
1112 | } |
||
1113 | // Standard mechanism for accepting permission changes from decorators |
||
1114 | $extended = $this->extendedCan(__FUNCTION__, $member); |
||
1115 | if ($extended !== null) { |
||
1116 | return $extended; |
||
1117 | } |
||
1118 | return $this->AllowPurchase; |
||
1119 | } |
||
1120 | |||
1121 | public function canCreate($member = null) |
||
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 ![]() |
|||
1122 | { |
||
1123 | if (! $member) { |
||
1124 | $member = Member::currentUser(); |
||
1125 | } |
||
1126 | $extended = $this->extendedCan(__FUNCTION__, $member); |
||
1127 | if ($extended !== null) { |
||
1128 | return $extended; |
||
1129 | } |
||
1130 | if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) { |
||
1131 | return true; |
||
1132 | } |
||
1133 | |||
1134 | return parent::canCreate($member); |
||
1135 | } |
||
1136 | |||
1137 | /** |
||
1138 | * Shop Admins can edit. |
||
1139 | * |
||
1140 | * @param Member $member |
||
0 ignored issues
–
show
Should the type for parameter
$member not be Member|null ?
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. ![]() |
|||
1141 | * |
||
1142 | * @return bool |
||
1143 | */ |
||
1144 | public function canEdit($member = null) |
||
1145 | { |
||
1146 | if (! $member) { |
||
1147 | $member = Member::currentUser(); |
||
1148 | } |
||
1149 | $extended = $this->extendedCan(__FUNCTION__, $member); |
||
1150 | if ($extended !== null) { |
||
1151 | return $extended; |
||
1152 | } |
||
1153 | if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) { |
||
1154 | return true; |
||
1155 | } |
||
1156 | |||
1157 | return parent::canEdit($member); |
||
1158 | } |
||
1159 | |||
1160 | /** |
||
1161 | * Standard SS method. |
||
1162 | * |
||
1163 | * @param Member $member |
||
0 ignored issues
–
show
Should the type for parameter
$member not be Member|null ?
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. ![]() |
|||
1164 | * |
||
1165 | * @return bool |
||
1166 | */ |
||
1167 | public function canDelete($member = null) |
||
1168 | { |
||
1169 | if (is_a(Controller::curr(), Object::getCustomClass('ProductsAndGroupsModelAdmin'))) { |
||
1170 | return false; |
||
1171 | } |
||
1172 | if (! $member) { |
||
1173 | $member = Member::currentUser(); |
||
1174 | } |
||
1175 | $extended = $this->extendedCan(__FUNCTION__, $member); |
||
1176 | if ($extended !== null) { |
||
1177 | return $extended; |
||
1178 | } |
||
1179 | |||
1180 | return $this->canEdit($member); |
||
1181 | } |
||
1182 | |||
1183 | /** |
||
1184 | * Standard SS method. |
||
1185 | * |
||
1186 | * @param Member $member |
||
0 ignored issues
–
show
Should the type for parameter
$member not be Member|null ?
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. ![]() |
|||
1187 | * |
||
1188 | * @return bool |
||
1189 | */ |
||
1190 | public function canPublish($member = null) |
||
1191 | { |
||
1192 | return $this->canEdit($member); |
||
1193 | } |
||
1194 | |||
1195 | |||
1196 | public function debug() |
||
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 ![]() |
|||
1197 | { |
||
1198 | $html = EcommerceTaskDebugCart::debug_object($this); |
||
1199 | $html .= '<ul>'; |
||
1200 | $html .= '<li><hr />Links<hr /></li>'; |
||
1201 | $html .= '<li><b>Link:</b> <a href="'.$this->Link().'">'.$this->Link().'</a></li>'; |
||
1202 | $html .= '<li><b>Ajax Link:</b> <a href="'.$this->AjaxLink().'">'.$this->AjaxLink().'</a></li>'; |
||
1203 | $html .= '<li><b>AddVariations Link:</b> <a href="'.$this->AddVariationsLink().'">'.$this->AddVariationsLink().'</a></li>'; |
||
1204 | $html .= '<li><b>Add to Cart Link:</b> <a href="'.$this->AddLink().'">'.$this->AddLink().'</a></li>'; |
||
1205 | $html .= '<li><b>Increment Link:</b> <a href="'.$this->IncrementLink().'">'.$this->IncrementLink().'</a></li>'; |
||
1206 | $html .= '<li><b>Decrement Link:</b> <a href="'.$this->DecrementLink().'">'.$this->DecrementLink().'</a></li>'; |
||
1207 | $html .= '<li><b>Remove Link:</b> <a href="'.$this->RemoveAllLink().'">'.$this->RemoveLink().'</a></li>'; |
||
1208 | $html .= '<li><b>Remove All Link:</b> <a href="'.$this->RemoveAllLink().'">'.$this->RemoveAllLink().'</a></li>'; |
||
1209 | $html .= '<li><b>Remove All and Edit Link:</b> <a href="'.$this->RemoveAllAndEditLink().'">'.$this->RemoveAllAndEditLink().'</a></li>'; |
||
1210 | $html .= '<li><b>Set Specific Quantity Item Link (e.g. 77):</b> <a href="'.$this->SetSpecificQuantityItemLink(77).'">'.$this->SetSpecificQuantityItemLink(77).'</a></li>'; |
||
1211 | |||
1212 | $html .= '<li><hr />Cart<hr /></li>'; |
||
1213 | $html .= '<li><b>Allow Purchase (DB Value):</b> '.$this->AllowPurchaseNice().' </li>'; |
||
1214 | $html .= '<li><b>Can Purchase (overal calculation):</b> '.($this->canPurchase() ? 'YES' : 'NO').' </li>'; |
||
1215 | $html .= '<li><b>Shop Open:</b> '.($this->EcomConfig() ? ($this->EcomConfig()->ShopClosed ? 'NO' : 'YES') : 'NO CONFIG').' </li>'; |
||
0 ignored issues
–
show
The property
ShopClosed does not exist on object<EcommerceDBConfig> . 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. ![]() |
|||
1216 | $html .= '<li><b>Extended Country Can Purchase:</b> '.($this->extendedCan('canPurchaseByCountry', null) === null ? 'no applicable' : ($this->extendedCan('canPurchaseByCountry', null) ? 'CAN PURCHASE' : 'CAN NOT PURCHASE')).' </li>'; |
||
1217 | $html .= '<li><b>Allow sales to this country ('.EcommerceCountry::get_country().'):</b> '.(EcommerceCountry::allow_sales() ? 'YES' : 'NO').' </li>'; |
||
1218 | $html .= '<li><b>Class Name for OrderItem:</b> '.$this->classNameForOrderItem().' </li>'; |
||
1219 | $html .= '<li><b>Quantity Decimals:</b> '.$this->QuantityDecimals().' </li>'; |
||
1220 | $html .= '<li><b>Is In Cart:</b> '.($this->IsInCart() ? 'YES' : 'NO').' </li>'; |
||
1221 | $html .= '<li><b>Has Been Sold:</b> '.($this->HasBeenSold() ? 'YES' : 'NO').' </li>'; |
||
1222 | $html .= '<li><b>Calculated Price:</b> '.$this->CalculatedPrice().' </li>'; |
||
1223 | $html .= '<li><b>Calculated Price as Money:</b> '.$this->getCalculatedPriceAsMoney()->Nice().' </li>'; |
||
1224 | |||
1225 | $html .= '<li><hr />Location<hr /></li>'; |
||
1226 | $html .= '<li><b>Main Parent Group:</b> '.$this->MainParentGroup()->Title.'</li>'; |
||
1227 | $html .= '<li><b>All Others Parent Groups:</b> '.($this->AllParentGroups()->count() ? '<pre>'.print_r($this->AllParentGroups()->map()->toArray(), 1).'</pre>' : 'none').'</li>'; |
||
1228 | |||
1229 | $html .= '<li><hr />Image<hr /></li>'; |
||
1230 | $html .= '<li><b>Image:</b> '.($this->BestAvailableImage() ? '<img src='.$this->BestAvailableImage()->Link().' />' : 'no image').' </li>'; |
||
1231 | $productGroup = ProductGroup::get()->byID($this->ParentID); |
||
1232 | if ($productGroup) { |
||
1233 | $html .= '<li><hr />Product Example<hr /></li>'; |
||
1234 | $html .= '<li><b>Product Group View:</b> <a href="'.$productGroup->Link().'">'.$productGroup->Title.'</a> </li>'; |
||
1235 | $html .= '<li><b>Product Group Debug:</b> <a href="'.$productGroup->Link('debug').'">'.$productGroup->Title.'</a> </li>'; |
||
1236 | $html .= '<li><b>Product Group Admin:</b> <a href="'.'/admin/pages/edit/show/'.$productGroup->ID.'">'.$productGroup->Title.' Admin</a> </li>'; |
||
1237 | $html .= '<li><b>Edit this Product:</b> <a href="'.'/admin/pages/edit/show/'.$this->ID.'">'.$this->Title.' Admin</a> </li>'; |
||
1238 | } |
||
1239 | $html .= '</ul>'; |
||
1240 | |||
1241 | return $html; |
||
1242 | $html .= '</ul>'; |
||
0 ignored issues
–
show
$html .= '</ul>'; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
1243 | |||
1244 | return $html; |
||
1245 | } |
||
1246 | |||
1247 | /** |
||
1248 | * |
||
1249 | * @int |
||
1250 | */ |
||
1251 | public function IDForSearchResults() |
||
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 ![]() |
|||
1252 | { |
||
1253 | return $this->ID; |
||
1254 | } |
||
1255 | |||
1256 | /** |
||
1257 | * |
||
1258 | * @string |
||
1259 | */ |
||
1260 | public function InternalItemIDForSearchResults() |
||
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 ![]() |
|||
1261 | { |
||
1262 | return $this->InternalItemID; |
||
1263 | } |
||
1264 | } |
||
1265 | |||
1266 | class Product_Controller extends Page_Controller |
||
1267 | { |
||
1268 | private static $allowed_actions = array( |
||
1269 | 'viewversion', |
||
1270 | 'ajaxview', |
||
1271 | 'addproductfromform', |
||
1272 | 'debug' => 'ADMIN', |
||
1273 | ); |
||
1274 | |||
1275 | /** |
||
1276 | * is this the current version? |
||
1277 | * |
||
1278 | * @var bool |
||
1279 | */ |
||
1280 | protected $isCurrentVersion = true; |
||
1281 | |||
1282 | /** |
||
1283 | * Standard SS method. |
||
1284 | */ |
||
1285 | public function init() |
||
1286 | { |
||
1287 | parent::init(); |
||
1288 | Requirements::themedCSS('Product', 'ecommerce'); |
||
1289 | Requirements::javascript('ecommerce/javascript/EcomProducts.js'); |
||
1290 | } |
||
1291 | |||
1292 | /** |
||
1293 | * view earlier version of a product |
||
1294 | * returns error or changes datarecord to earlier version |
||
1295 | * if the ID does not match the Page then we look for the variation. |
||
1296 | * |
||
1297 | * @param SS_HTTPRequest |
||
1298 | */ |
||
1299 | public function viewversion(SS_HTTPRequest $request) |
||
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 ![]() |
|||
1300 | { |
||
1301 | $version = intval($request->param('ID')) - 0; |
||
1302 | $currentVersion = $this->Version; |
||
1303 | if ($currentVersion != $version) { |
||
1304 | if ($record = $this->getVersionOfBuyable($this->ID, $version)) { |
||
1305 | //we check again, because we may actually get the same version back... |
||
1306 | if ($record->Version != $this->Version) { |
||
1307 | $this->record = $record; |
||
1308 | $this->dataRecord->AllowPurchase = false; |
||
1309 | $this->AllowPurchase = false; |
||
1310 | $this->isCurrentVersion = false; |
||
1311 | $this->Title .= _t('Product.OLDERVERSION', ' - Older Version'); |
||
1312 | $this->MetaTitle .= _t('Product.OLDERVERSION', ' - Older Version'); |
||
1313 | } |
||
1314 | } else { |
||
1315 | return $this->httpError(404); |
||
1316 | } |
||
1317 | } |
||
1318 | |||
1319 | return array(); |
||
1320 | } |
||
1321 | |||
1322 | /** |
||
1323 | * Standard SS method |
||
1324 | * Returns a snippet when requested by ajax. |
||
1325 | */ |
||
1326 | public function ajaxview(SS_HTTPRequest $request) |
||
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 ![]() |
|||
1327 | { |
||
1328 | Config::nest(); |
||
1329 | Config::inst()->update('SSViewer', 'theme_enabled', true); |
||
1330 | $html = $this->renderWith('ProductGroupItemMoreDetail'); |
||
1331 | Config::unnest(); |
||
1332 | |||
1333 | return $html; |
||
1334 | } |
||
1335 | |||
1336 | /** |
||
1337 | * returns a form for adding products to cart. |
||
1338 | * |
||
1339 | * @return Form |
||
1340 | */ |
||
1341 | public function AddProductForm() |
||
1342 | { |
||
1343 | if ($this->canPurchase()) { |
||
1344 | $farray = array(); |
||
1345 | $requiredFields = array(); |
||
0 ignored issues
–
show
$requiredFields 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 ![]() |
|||
1346 | $fields = new FieldList($farray); |
||
1347 | $fields->push(new NumericField('Quantity', 'Quantity', 1)); //TODO: perhaps use a dropdown instead (elimiates need to use keyboard) |
||
1348 | $actions = new FieldList( |
||
1349 | new FormAction('addproductfromform', _t('Product.ADDLINK', 'Add this item to cart')) |
||
1350 | ); |
||
1351 | $requiredfields[] = 'Quantity'; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$requiredfields was never initialized. Although not strictly required by PHP, it is generally a good practice to add $requiredfields = 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. ![]() |
|||
1352 | $validator = new RequiredFields($requiredfields); |
||
1353 | $form = new Form($this, 'AddProductForm', $fields, $actions, $validator); |
||
1354 | |||
1355 | return $form; |
||
1356 | } else { |
||
1357 | return _t('Product.PRODUCTNOTFORSALE', 'Product not for sale'); |
||
1358 | } |
||
1359 | } |
||
1360 | |||
1361 | /** |
||
1362 | * executes the AddProductForm. |
||
1363 | * |
||
1364 | * @param array $data |
||
1365 | * @param Form $form |
||
1366 | */ |
||
1367 | public function addproductfromform(array $data, Form $form) |
||
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 ![]() |
|||
1368 | { |
||
1369 | if (!$this->IsInCart()) { |
||
1370 | $quantity = round($data['Quantity'], $this->QuantityDecimals()); |
||
1371 | if (!$quantity) { |
||
1372 | $quantity = 1; |
||
1373 | } |
||
1374 | $product = Product::get()->byID($this->ID); |
||
1375 | if ($product) { |
||
1376 | ShoppingCart::singleton()->addBuyable($product, $quantity); |
||
1377 | } |
||
1378 | if ($this->IsInCart()) { |
||
1379 | $msg = _t('Order.SUCCESSFULLYADDED', 'Added to cart.'); |
||
1380 | $status = 'good'; |
||
1381 | } else { |
||
1382 | $msg = _t('Order.NOTADDEDTOCART', 'Not added to cart.'); |
||
1383 | $status = 'bad'; |
||
1384 | } |
||
1385 | if (Director::is_ajax()) { |
||
1386 | return ShoppingCart::singleton()->setMessageAndReturn($msg, $status); |
||
1387 | } else { |
||
1388 | $form->sessionMessage($msg, $status); |
||
1389 | $this->redirectBack(); |
||
1390 | } |
||
1391 | } else { |
||
1392 | return EcomQuantityField::create($this); |
||
1393 | } |
||
1394 | } |
||
1395 | |||
1396 | /** |
||
1397 | * Is this an older version? |
||
1398 | * |
||
1399 | * @return bool |
||
1400 | */ |
||
1401 | public function IsOlderVersion() |
||
1402 | { |
||
1403 | return $this->isCurrentVersion ? false : true; |
||
1404 | } |
||
1405 | |||
1406 | /** |
||
1407 | * This method can be extended to show products in the side bar. |
||
1408 | * |
||
1409 | * @return DataList (Products) |
||
0 ignored issues
–
show
|
|||
1410 | */ |
||
1411 | public function SidebarProducts() |
||
1412 | { |
||
1413 | return; |
||
1414 | } |
||
1415 | |||
1416 | /** |
||
1417 | * This method can be extended to show products in the side bar. |
||
1418 | * |
||
1419 | * @return Product | Null |
||
1420 | */ |
||
1421 | public function NextProduct() |
||
1422 | { |
||
1423 | $array = $this->getListOfIDs(); |
||
1424 | $next = 0; |
||
0 ignored issues
–
show
$next 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 ![]() |
|||
1425 | foreach ($array as $key => $id) { |
||
1426 | $id = intval($id); |
||
1427 | if ($id == $this->ID) { |
||
1428 | if (isset($array[$key + 1])) { |
||
1429 | return Product::get()->byID(intval($array[$key + 1])); |
||
1430 | } |
||
1431 | } |
||
1432 | } |
||
1433 | } |
||
1434 | |||
1435 | /** |
||
1436 | * This method can be extended to show products in the side bar. |
||
1437 | * |
||
1438 | * @return Product | Null |
||
1439 | */ |
||
1440 | public function PreviousProduct() |
||
1441 | { |
||
1442 | $array = $this->getListOfIDs(); |
||
1443 | $previousID = 0; |
||
1444 | foreach ($array as $key => $id) { |
||
1445 | $id = intval($id); |
||
1446 | if ($id == $this->ID) { |
||
1447 | return Product::get()->byID($previousID); |
||
1448 | } |
||
1449 | $previousID = $id; |
||
1450 | } |
||
1451 | |||
1452 | return; |
||
1453 | } |
||
1454 | |||
1455 | /** |
||
1456 | * This method can be extended to show products in the side bar. |
||
1457 | * |
||
1458 | * @return bool |
||
1459 | */ |
||
1460 | public function HasPreviousOrNextProduct() |
||
1461 | { |
||
1462 | return $this->PreviousProduct() || $this->NextProduct() ? true : false; |
||
1463 | } |
||
1464 | |||
1465 | /** |
||
1466 | * returns an array of product IDs, as saved in the last |
||
1467 | * ProductGroup view (saved using session). |
||
1468 | * |
||
1469 | * @return array |
||
1470 | */ |
||
1471 | protected function getListOfIDs() |
||
1472 | { |
||
1473 | $listOfIDs = Session::get(EcommerceConfig::get('ProductGroup', 'session_name_for_product_array')); |
||
1474 | if ($listOfIDs) { |
||
1475 | $arrayOfIDs = explode(',', $listOfIDs); |
||
1476 | if (is_array($arrayOfIDs)) { |
||
1477 | return $arrayOfIDs; |
||
1478 | } |
||
1479 | } |
||
1480 | |||
1481 | return array(); |
||
1482 | } |
||
1483 | |||
1484 | public function debug() |
||
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 ![]() |
|||
1485 | { |
||
1486 | $member = Member::currentUser(); |
||
1487 | if (!$member || !$member->IsShopAdmin()) { |
||
1488 | $messages = array( |
||
1489 | 'default' => 'You must login as an admin to access debug functions.', |
||
1490 | ); |
||
1491 | Security::permissionFailure($this, $messages); |
||
1492 | } |
||
1493 | |||
1494 | return $this->dataRecord->debug(); |
||
1495 | } |
||
1496 | } |
||
1497 |
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
@return
annotation as described here.