These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * ShoppingCart - provides a global way to interface with the cart (current order). |
||
4 | * |
||
5 | * This can be used in other code by calling $cart = ShoppingCart::singleton(); |
||
6 | * |
||
7 | * The shopping cart can be accessed as an order handler from the back-end |
||
8 | * (e.g. when creating an order programmatically), while the accompagnying controller |
||
9 | * is used by web-users to manipulate their order. |
||
10 | * |
||
11 | * A bunch of core functions are also stored in the order itself. |
||
12 | * Methods and variables are in the shopping cart if they are relevant |
||
13 | * only before (and while) the order is placed (e.g. latest update message), |
||
14 | * and others are in the order because they are relevant even after the |
||
15 | * order has been submitted (e.g. Total Cost). |
||
16 | * |
||
17 | * Key methods: |
||
18 | * |
||
19 | * //get Cart |
||
20 | * $myCart = ShoppingCart::singleton(); |
||
21 | * |
||
22 | * //get order |
||
23 | * $myOrder = ShoppingCart::current_order(); |
||
24 | * |
||
25 | * //view order (from another controller) |
||
26 | * $this->redirect(ShoppingCart::current_order()->Link()); |
||
27 | * |
||
28 | * //add item to cart |
||
29 | * ShoppingCart::singleton()->addBuyable($myProduct); |
||
30 | * |
||
31 | * @authors: Nicolaas [at] Sunny Side Up .co.nz |
||
32 | * @package: ecommerce |
||
33 | * @sub-package: control |
||
34 | * @inspiration: Silverstripe Ltd, Jeremy |
||
35 | **/ |
||
36 | class ShoppingCart extends Object |
||
37 | { |
||
38 | /** |
||
39 | * List of names that can be used as session variables. |
||
40 | * Also @see ShoppingCart::sessionVariableName. |
||
41 | * |
||
42 | * @var array |
||
43 | */ |
||
44 | private static $session_variable_names = array('OrderID', 'Messages'); |
||
45 | |||
46 | /** |
||
47 | * This is where we hold the (singleton) Shoppingcart. |
||
48 | * |
||
49 | * @var object (ShoppingCart) |
||
50 | */ |
||
51 | private static $_singletoncart = null; |
||
52 | |||
53 | /** |
||
54 | * Feedback message to user (e.g. cart updated, could not delete item, someone in standing behind you). |
||
55 | * |
||
56 | *@var array |
||
57 | **/ |
||
58 | protected $messages = array(); |
||
59 | |||
60 | /** |
||
61 | * stores a reference to the current order object. |
||
62 | * |
||
63 | * @var object |
||
64 | **/ |
||
65 | protected $order = null; |
||
66 | |||
67 | /** |
||
68 | * This variable is set to YES when we actually need an order (i.e. write it). |
||
69 | * |
||
70 | * @var bool |
||
71 | */ |
||
72 | protected $requireSavedOrder = false; |
||
73 | |||
74 | /** |
||
75 | * Allows access to the cart from anywhere in code. |
||
76 | * |
||
77 | * @return ShoppingCart Object |
||
78 | */ |
||
79 | public static function singleton() |
||
80 | { |
||
81 | if (!self::$_singletoncart) { |
||
82 | self::$_singletoncart = Injector::inst()->get('ShoppingCart'); |
||
83 | } |
||
84 | |||
85 | return self::$_singletoncart; |
||
86 | } |
||
87 | |||
88 | /** |
||
89 | * Allows access to the current order from anywhere in the code.. |
||
90 | * |
||
91 | * if you do not like the session Order then you can set it here ... |
||
92 | * |
||
93 | * @param Order $order (optional) |
||
0 ignored issues
–
show
|
|||
94 | * |
||
95 | * @return Order |
||
96 | */ |
||
97 | public static function current_order($order = null) |
||
98 | { |
||
99 | return self::singleton()->currentOrder(0, $order); |
||
100 | } |
||
101 | |||
102 | /** |
||
103 | * looks up current order id. |
||
104 | * you may supply an ID here, so that it looks up the current order ID |
||
105 | * only when none is supplied. |
||
106 | * |
||
107 | * @param int (optional) | Order $orderOrOrderID |
||
108 | * |
||
109 | * @return int; |
||
0 ignored issues
–
show
The doc-type
int; could not be parsed: Expected "|" or "end of type", but got ";" at position 3. (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.
Loading history...
|
|||
110 | */ |
||
111 | public static function current_order_id($orderOrOrderID = 0) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a
Loading history...
|
|||
112 | { |
||
113 | $orderID = 0; |
||
114 | if (!$orderOrOrderID) { |
||
115 | $order = self::current_order(); |
||
116 | if ($order && $order->exists()) { |
||
117 | $orderID = $order->ID; |
||
118 | } |
||
119 | } |
||
120 | if($orderOrOrderID instanceof Order) { |
||
121 | $orderID = $orderOrOrderID->ID; |
||
122 | } elseif(intval($orderOrOrderID)) { |
||
123 | $orderID = intval($orderOrOrderID); |
||
124 | } |
||
125 | |||
126 | return $orderID; |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * Allows access to the current order from anywhere in the code.. |
||
131 | * |
||
132 | * @return Order |
||
0 ignored issues
–
show
|
|||
133 | */ |
||
134 | public static function session_order() |
||
135 | { |
||
136 | $sessionVariableName = self::singleton()->sessionVariableName('OrderID'); |
||
137 | $orderIDFromSession = intval(Session::get($sessionVariableName)) - 0; |
||
138 | |||
139 | return Order::get()->byID($orderIDFromSession); |
||
140 | } |
||
141 | |||
142 | /** |
||
143 | * set a specific order, other than the one from session .... |
||
144 | * |
||
145 | * @param Order $order |
||
146 | * |
||
147 | * @return Order |
||
148 | */ |
||
149 | public function setOrder($order) |
||
150 | { |
||
151 | $this->order = $order; |
||
152 | return $this->order; |
||
153 | } |
||
154 | |||
155 | /** |
||
156 | * Gets or creates the current order. |
||
157 | * Based on the session ONLY unless the order has been explictely set. |
||
158 | * IMPORTANT FUNCTION! |
||
159 | * |
||
160 | * returns null if the current user does not allow order manipulation or saving (e.g. session disabled) |
||
161 | * |
||
162 | * However, you can pass an order in case you want to manipulate an order that is not in sesssion |
||
163 | * |
||
164 | * @param int $recurseCount (optional) |
||
165 | * @param Order $order (optional) |
||
0 ignored issues
–
show
Should the type for parameter
$order not be Order|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.
Loading history...
|
|||
166 | * |
||
167 | * @return Order |
||
168 | */ |
||
169 | public function currentOrder($recurseCount = 0, $order = null) |
||
170 | { |
||
171 | if($order) { |
||
172 | $this->order = $order; |
||
173 | } |
||
174 | if($this->allowWrites()) { |
||
175 | if (!$this->order) { |
||
176 | $this->order = self::session_order(); |
||
177 | $loggedInMember = Member::currentUser(); |
||
178 | if ($this->order) { |
||
179 | //first reason to set to null: it is already submitted |
||
180 | if ($this->order->IsSubmitted()) { |
||
181 | $this->order = null; |
||
182 | } |
||
183 | //second reason to set to null: make sure we have permissions |
||
184 | elseif (!$this->order->canView()) { |
||
185 | $this->order = null; |
||
186 | } |
||
187 | //logged in, add Member.ID to order->MemberID |
||
188 | elseif ($loggedInMember && $loggedInMember->exists()) { |
||
189 | if ($this->order->MemberID != $loggedInMember->ID) { |
||
0 ignored issues
–
show
The property
MemberID does not exist on object<Order> . 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.
Loading history...
|
|||
190 | $updateMember = false; |
||
191 | if (!$this->order->MemberID) { |
||
0 ignored issues
–
show
The property
MemberID does not exist on object<Order> . 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.
Loading history...
|
|||
192 | $updateMember = true; |
||
193 | } |
||
194 | if (!$loggedInMember->IsShopAdmin()) { |
||
195 | $updateMember = true; |
||
196 | } |
||
197 | if ($updateMember) { |
||
198 | $this->order->MemberID = $loggedInMember->ID; |
||
0 ignored issues
–
show
The property
MemberID does not exist on object<Order> . Since you implemented __set , maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
199 | $this->order->write(); |
||
200 | } |
||
201 | } |
||
202 | //IF current order has nothing in it AND the member already has an order: use the old one first |
||
203 | //first, lets check if the current order is worthwhile keeping |
||
204 | if ($this->order->StatusID || $this->order->TotalItems()) { |
||
0 ignored issues
–
show
The property
StatusID does not exist on object<Order> . 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.
Loading history...
|
|||
205 | //do NOTHING! |
||
206 | } else { |
||
207 | $firstStep = OrderStep::get()->First(); |
||
208 | //we assume the first step always exists. |
||
209 | //TODO: what sort order? |
||
210 | $count = 0; |
||
211 | while ( |
||
212 | $firstStep && |
||
213 | $previousOrderFromMember = Order::get() |
||
214 | ->where(' |
||
215 | "MemberID" = '.$loggedInMember->ID.' |
||
216 | AND ("StatusID" = '.$firstStep->ID.' OR "StatusID" = 0) |
||
217 | AND "Order"."ID" <> '.$this->order->ID |
||
218 | ) |
||
219 | ->First() |
||
220 | ) { |
||
221 | //arbritary 12 attempts ... |
||
222 | if ($count > 12) { |
||
223 | break; |
||
224 | } |
||
225 | ++$count; |
||
226 | if ($previousOrderFromMember && $previousOrderFromMember->canView()) { |
||
227 | if ($previousOrderFromMember->StatusID || $previousOrderFromMember->TotalItems()) { |
||
228 | $this->order->delete(); |
||
229 | $this->order = $previousOrderFromMember; |
||
230 | break; |
||
231 | } else { |
||
232 | $previousOrderFromMember->delete(); |
||
233 | } |
||
234 | } |
||
235 | } |
||
236 | } |
||
237 | } |
||
238 | } |
||
239 | if (! $this->order) { |
||
240 | if ($loggedInMember) { |
||
241 | //find previour order... |
||
242 | $firstStep = OrderStep::get()->First(); |
||
243 | if ($firstStep) { |
||
244 | $previousOrderFromMember = Order::get() |
||
245 | ->filter(array( |
||
246 | 'MemberID' => $loggedInMember->ID, |
||
247 | 'StatusID' => array($firstStep->ID, 0), |
||
248 | )) |
||
249 | ->First(); |
||
250 | if ($previousOrderFromMember) { |
||
251 | if ($previousOrderFromMember->canView()) { |
||
252 | $this->order = $previousOrderFromMember; |
||
253 | } |
||
254 | } |
||
255 | } |
||
256 | } |
||
257 | if ($this->order && !$this->order->exists()) { |
||
258 | $this->order = null; |
||
259 | } |
||
260 | if (! $this->order) { |
||
261 | //here we cleanup old orders, because they should be |
||
262 | //cleaned at the same rate that they are created... |
||
263 | if (EcommerceConfig::get('ShoppingCart', 'cleanup_every_time')) { |
||
264 | $cartCleanupTask = EcommerceTaskCartCleanup::create(); |
||
265 | $cartCleanupTask->runSilently(); |
||
266 | } |
||
267 | //create new order |
||
268 | $this->order = Order::create(); |
||
269 | if ($loggedInMember) { |
||
270 | $this->order->MemberID = $loggedInMember->ID; |
||
0 ignored issues
–
show
The property
MemberID does not exist on object<Order> . Since you implemented __set , maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
271 | } |
||
272 | $this->order->write(); |
||
273 | } |
||
274 | $sessionVariableName = $this->sessionVariableName('OrderID'); |
||
275 | Session::set($sessionVariableName, intval($this->order->ID)); |
||
276 | } |
||
277 | if ($this->order){ |
||
278 | if($this->order->exists()) { |
||
279 | $this->order->calculateOrderAttributes($force = false); |
||
280 | } |
||
281 | if (! $this->order->SessionID) { |
||
282 | $this->order->write(); |
||
283 | } |
||
284 | //add session ID... |
||
285 | } |
||
286 | } |
||
287 | //try it again |
||
288 | //but limit to three, just in case ... |
||
289 | //just in case ... |
||
290 | if (!$this->order && $recurseCount < 3) { |
||
291 | ++$recurseCount; |
||
292 | |||
293 | return $this->currentOrder($recurseCount, $order); |
||
294 | } |
||
295 | |||
296 | return $this->order; |
||
297 | } else { |
||
298 | |||
299 | //we still return an order so that we do not end up with errors... |
||
300 | return Order::create(); |
||
301 | } |
||
302 | } |
||
303 | |||
304 | |||
305 | private static $_allow_writes_cache = null; |
||
306 | |||
307 | /** |
||
308 | * can the current user use sessions and therefore write to cart??? |
||
309 | * the method also returns if an order has explicitely been set |
||
310 | * @return Boolean |
||
311 | */ |
||
312 | protected function allowWrites() |
||
313 | { |
||
314 | if(self::$_allow_writes_cache === null) { |
||
315 | if($this->order) { |
||
316 | self::$_allow_writes_cache = true; |
||
317 | } else { |
||
318 | if ( php_sapi_name() !== 'cli' ) { |
||
319 | if ( version_compare(phpversion(), '5.4.0', '>=') ) { |
||
320 | self::$_allow_writes_cache = session_status() === PHP_SESSION_ACTIVE ? true : false; |
||
321 | } else { |
||
322 | self::$_allow_writes_cache = session_id() === '' ? true : false; |
||
323 | } |
||
324 | } else { |
||
325 | self::$_allow_writes_cache = false; |
||
326 | } |
||
327 | } |
||
328 | } |
||
329 | |||
330 | return self::$_allow_writes_cache; |
||
331 | |||
332 | } |
||
333 | |||
334 | /** |
||
335 | * Allows access to the current order from anywhere in the code.. |
||
336 | * |
||
337 | * @param Order $order (optional) |
||
0 ignored issues
–
show
Should the type for parameter
$order not be Order|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.
Loading history...
|
|||
338 | * |
||
339 | * @return ShoppingCart Object |
||
340 | */ |
||
341 | public function Link($order = null) |
||
342 | { |
||
343 | $order = self::singleton()->currentOrder(0, $order = null); |
||
344 | if ($order) { |
||
345 | return $order->Link(); |
||
346 | } |
||
347 | } |
||
348 | |||
349 | /** |
||
350 | * Adds any number of items to the cart. |
||
351 | * Returns the order item on succes OR false on failure. |
||
352 | * |
||
353 | * @param DataObject $buyable - the buyable (generally a product) being added to the cart |
||
0 ignored issues
–
show
Should the type for parameter
$buyable not be BuyableModel ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
354 | * @param float $quantity - number of items add. |
||
0 ignored issues
–
show
Should the type for parameter
$quantity not be integer ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
355 | * @param mixed $parameters - array of parameters to target a specific order item. eg: group=1, length=5 |
||
356 | * if you make it a form, it will save the form into the orderitem |
||
357 | * returns null if the current user does not allow order manipulation or saving (e.g. session disabled) |
||
358 | * |
||
359 | * @return false | DataObject (OrderItem) |
||
0 ignored issues
–
show
|
|||
360 | */ |
||
361 | public function addBuyable(BuyableModel $buyable, $quantity = 1, $parameters = array()) |
||
362 | { |
||
363 | if($this->allowWrites()) { |
||
364 | if (!$buyable) { |
||
365 | $this->addMessage(_t('Order.ITEMCOULDNOTBEFOUND', 'This item could not be found.'), 'bad'); |
||
366 | return false; |
||
367 | } |
||
368 | if (!$buyable->canPurchase()) { |
||
369 | $this->addMessage(_t('Order.ITEMCOULDNOTBEADDED', 'This item is not for sale.'), 'bad'); |
||
370 | return false; |
||
371 | } |
||
372 | $item = $this->prepareOrderItem($buyable, $parameters, $mustBeExistingItem = false); |
||
373 | $quantity = $this->prepareQuantity($buyable, $quantity); |
||
374 | if ($item && $quantity) { //find existing order item or make one |
||
375 | $item->Quantity += $quantity; |
||
0 ignored issues
–
show
The property
Quantity does not exist on object<OrderItem> . Since you implemented __set , maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
376 | $item->write(); |
||
377 | $this->currentOrder()->Attributes()->add($item); //save to current order |
||
378 | //TODO: distinquish between incremented and set |
||
379 | //TODO: use sprintf to allow product name etc to be included in message |
||
380 | if ($quantity > 1) { |
||
381 | $msg = _t('Order.ITEMSADDED', 'Items added.'); |
||
382 | } else { |
||
383 | $msg = _t('Order.ITEMADDED', 'Item added.'); |
||
384 | } |
||
385 | $this->addMessage($msg, 'good'); |
||
386 | } elseif (!$item) { |
||
387 | $this->addMessage(_t('Order.ITEMNOTFOUND', 'Item could not be found.'), 'bad'); |
||
388 | } else { |
||
389 | $this->addMessage(_t('Order.ITEMCOULDNOTBEADDED', 'Item could not be added.'), 'bad'); |
||
390 | } |
||
391 | |||
392 | return $item; |
||
393 | } |
||
394 | } |
||
395 | |||
396 | /** |
||
397 | * Sets quantity for an item in the cart. |
||
398 | * |
||
399 | * returns null if the current user does not allow order manipulation or saving (e.g. session disabled) |
||
400 | * |
||
401 | * @param DataObject $buyable - the buyable (generally a product) being added to the cart |
||
0 ignored issues
–
show
Should the type for parameter
$buyable not be BuyableModel ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
402 | * @param float $quantity - number of items add. |
||
403 | * @param array $parameters - array of parameters to target a specific order item. eg: group=1, length=5 |
||
404 | * |
||
405 | * @return false | DataObject (OrderItem) | null |
||
0 ignored issues
–
show
|
|||
406 | */ |
||
407 | public function setQuantity(BuyableModel $buyable, $quantity, array $parameters = array()) |
||
408 | { |
||
409 | if($this->allowWrites()) { |
||
410 | $item = $this->prepareOrderItem($buyable, $parameters, $mustBeExistingItem = false); |
||
411 | $quantity = $this->prepareQuantity($buyable, $quantity); |
||
412 | if ($item) { |
||
413 | $item->Quantity = $quantity; //remove quantity |
||
0 ignored issues
–
show
The property
Quantity does not exist on object<OrderItem> . Since you implemented __set , maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
414 | $item->write(); |
||
415 | $this->addMessage(_t('Order.ITEMUPDATED', 'Item updated.'), 'good'); |
||
416 | |||
417 | return $item; |
||
418 | } else { |
||
419 | $this->addMessage(_t('Order.ITEMNOTFOUND', 'Item could not be found.'), 'bad'); |
||
420 | } |
||
421 | |||
422 | return false; |
||
423 | } |
||
424 | } |
||
425 | |||
426 | /** |
||
427 | * Removes any number of items from the cart. |
||
428 | * |
||
429 | * returns null if the current user does not allow order manipulation or saving (e.g. session disabled) |
||
430 | * |
||
431 | * @param DataObject $buyable - the buyable (generally a product) being added to the cart |
||
0 ignored issues
–
show
Should the type for parameter
$buyable not be BuyableModel ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
432 | * @param float $quantity - number of items add. |
||
0 ignored issues
–
show
Should the type for parameter
$quantity not be integer ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
433 | * @param array $parameters - array of parameters to target a specific order item. eg: group=1, length=5 |
||
434 | * |
||
435 | * @return false | OrderItem | null |
||
0 ignored issues
–
show
|
|||
436 | */ |
||
437 | public function decrementBuyable(BuyableModel $buyable, $quantity = 1, array $parameters = array()) |
||
438 | { |
||
439 | if($this->allowWrites()) { |
||
440 | $item = $this->prepareOrderItem($buyable, $parameters, $mustBeExistingItem = false); |
||
441 | $quantity = $this->prepareQuantity($buyable, $quantity); |
||
442 | if ($item) { |
||
443 | $item->Quantity -= $quantity; //remove quantity |
||
0 ignored issues
–
show
The property
Quantity does not exist on object<OrderItem> . Since you implemented __set , maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
444 | if ($item->Quantity < 0) { |
||
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.
Loading history...
|
|||
445 | $item->Quantity = 0; |
||
0 ignored issues
–
show
The property
Quantity does not exist on object<OrderItem> . Since you implemented __set , maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
446 | } |
||
447 | $item->write(); |
||
448 | if ($quantity > 1) { |
||
449 | $msg = _t('Order.ITEMSREMOVED', 'Items removed.'); |
||
450 | } else { |
||
451 | $msg = _t('Order.ITEMREMOVED', 'Item removed.'); |
||
452 | } |
||
453 | $this->addMessage($msg, 'good'); |
||
454 | |||
455 | return $item; |
||
456 | } else { |
||
457 | $this->addMessage(_t('Order.ITEMNOTFOUND', 'Item could not be found.'), 'bad'); |
||
458 | } |
||
459 | |||
460 | return false; |
||
461 | } |
||
462 | |||
463 | } |
||
464 | |||
465 | /** |
||
466 | * Delete item from the cart. |
||
467 | * |
||
468 | * returns null if the current user does not allow order manipulation or saving (e.g. session disabled) |
||
469 | * |
||
470 | * @param OrderItem $buyable - the buyable (generally a product) being added to the cart |
||
0 ignored issues
–
show
Should the type for parameter
$buyable not be BuyableModel ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
471 | * @param array $parameters - array of parameters to target a specific order item. eg: group=1, length=5 |
||
472 | * |
||
473 | * @return bool | item | null - successfully removed |
||
0 ignored issues
–
show
|
|||
474 | */ |
||
475 | public function deleteBuyable(BuyableModel $buyable, array $parameters = array()) |
||
476 | { |
||
477 | if($this->allowWrites()) { |
||
478 | $item = $this->prepareOrderItem($buyable, $parameters, $mustBeExistingItem = true); |
||
479 | if ($item) { |
||
480 | $this->currentOrder()->Attributes()->remove($item); |
||
481 | $item->delete(); |
||
482 | $item->destroy(); |
||
483 | $this->addMessage(_t('Order.ITEMCOMPLETELYREMOVED', 'Item removed from cart.'), 'good'); |
||
484 | |||
485 | return $item; |
||
486 | } else { |
||
487 | $this->addMessage(_t('Order.ITEMNOTFOUND', 'Item could not be found.'), 'bad'); |
||
488 | |||
489 | return false; |
||
490 | } |
||
491 | } |
||
492 | } |
||
493 | |||
494 | /** |
||
495 | * Checks and prepares variables for a quantity change (add, edit, remove) for an Order Item. |
||
496 | * |
||
497 | * @param DataObject $buyable - the buyable (generally a product) being added to the cart |
||
0 ignored issues
–
show
Should the type for parameter
$buyable not be BuyableModel ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
498 | * @param float $quantity - number of items add. |
||
499 | * @param bool $mustBeExistingItems - if false, the Order Item gets created if it does not exist - if TRUE the order item is searched for and an error shows if there is no Order item. |
||
0 ignored issues
–
show
There is no parameter named
$mustBeExistingItems . Did you maybe mean $mustBeExistingItem ?
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.
Loading history...
|
|||
500 | * @param array | Form $parameters - array of parameters to target a specific order item. eg: group=1, length=5* |
||
501 | * - form saved into item... |
||
502 | * |
||
503 | * @return bool | DataObject ($orderItem) |
||
0 ignored issues
–
show
|
|||
504 | */ |
||
505 | protected function prepareOrderItem(BuyableModel $buyable, $parameters = array(), $mustBeExistingItem = true) |
||
506 | { |
||
507 | $parametersArray = $parameters; |
||
508 | $form = null; |
||
509 | if ($parameters instanceof Form) { |
||
510 | $parametersArray = array(); |
||
511 | $form = $parameters; |
||
512 | } |
||
513 | if (!$buyable) { |
||
514 | user_error('No buyable was provided', E_USER_WARNING); |
||
515 | } |
||
516 | if (!$buyable->canPurchase()) { |
||
517 | $item = $this->getExistingItem($buyable, $parametersArray); |
||
518 | if ($item && $item->exists()) { |
||
519 | $item->delete(); |
||
520 | $item->destroy(); |
||
521 | } |
||
522 | |||
523 | return false; |
||
524 | } |
||
525 | $item = null; |
||
526 | if ($mustBeExistingItem) { |
||
527 | $item = $this->getExistingItem($buyable, $parametersArray); |
||
528 | } else { |
||
529 | $item = $this->findOrMakeItem($buyable, $parametersArray); //find existing order item or make one |
||
530 | } |
||
531 | if (!$item) { |
||
532 | //check for existence of item |
||
533 | return false; |
||
534 | } |
||
535 | if ($form) { |
||
536 | $form->saveInto($item); |
||
537 | } |
||
538 | |||
539 | return $item; |
||
540 | } |
||
541 | |||
542 | /** |
||
543 | * @todo: what does this method do??? |
||
544 | * |
||
545 | * @return int |
||
0 ignored issues
–
show
|
|||
546 | * |
||
547 | * @param DataObject ($buyable) |
||
548 | * @param float $quantity |
||
549 | */ |
||
550 | protected function prepareQuantity(BuyableModel $buyable, $quantity) |
||
551 | { |
||
552 | $quantity = round($quantity, $buyable->QuantityDecimals()); |
||
553 | if ($quantity < 0 || (!$quantity && $quantity !== 0)) { |
||
554 | $this->addMessage(_t('Order.INVALIDQUANTITY', 'Invalid quantity.'), 'warning'); |
||
555 | |||
556 | return false; |
||
557 | } |
||
558 | |||
559 | return $quantity; |
||
560 | } |
||
561 | |||
562 | /** |
||
563 | * Helper function for making / retrieving order items. |
||
564 | * we do not need things like "canPurchase" here, because that is with the "addBuyable" method. |
||
565 | * NOTE: does not write! |
||
566 | * |
||
567 | * @param DataObject $buyable |
||
0 ignored issues
–
show
Should the type for parameter
$buyable not be BuyableModel ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
568 | * @param array $parameters |
||
569 | * |
||
570 | * @return OrderItem |
||
571 | */ |
||
572 | public function findOrMakeItem(BuyableModel $buyable, array $parameters = array()) |
||
573 | { |
||
574 | if($this->allowWrites()) { |
||
575 | if ($item = $this->getExistingItem($buyable, $parameters)) { |
||
576 | //do nothing |
||
577 | } else { |
||
578 | //otherwise create a new item |
||
579 | if (!($buyable instanceof BuyableModel)) { |
||
580 | $this->addMessage(_t('ShoppingCart.ITEMNOTFOUND', 'Item is not buyable.'), 'bad'); |
||
581 | |||
582 | return false; |
||
583 | } |
||
584 | $className = $buyable->classNameForOrderItem(); |
||
585 | $item = new $className(); |
||
586 | if ($order = $this->currentOrder()) { |
||
587 | $item->OrderID = $order->ID; |
||
588 | $item->BuyableID = $buyable->ID; |
||
589 | $item->BuyableClassName = $buyable->ClassName; |
||
590 | if (isset($buyable->Version)) { |
||
591 | $item->Version = $buyable->Version; |
||
592 | } |
||
593 | } |
||
594 | } |
||
595 | if ($parameters) { |
||
596 | $item->Parameters = $parameters; |
||
597 | } |
||
598 | |||
599 | return $item; |
||
600 | } else { |
||
601 | return OrderItem::create(); |
||
602 | } |
||
603 | } |
||
604 | |||
605 | /** |
||
606 | * submit the order so that it is no longer available |
||
607 | * in the cart but will continue its journey through the |
||
608 | * order steps. |
||
609 | * |
||
610 | * @return bool |
||
611 | */ |
||
612 | public function submit() |
||
613 | { |
||
614 | if($this->allowWrites()) { |
||
615 | $this->currentOrder()->tryToFinaliseOrder(); |
||
616 | $this->clear(); |
||
617 | //little hack to clear static memory |
||
618 | OrderItem::reset_price_has_been_fixed($this->currentOrder()->ID); |
||
619 | |||
620 | return true; |
||
621 | } |
||
622 | |||
623 | return false; |
||
624 | } |
||
625 | |||
626 | /** |
||
627 | * returns null if the current user does not allow order manipulation or saving (e.g. session disabled) |
||
628 | * |
||
629 | * @return bool | null |
||
0 ignored issues
–
show
|
|||
630 | */ |
||
631 | public function save() |
||
632 | { |
||
633 | if($this->allowWrites()) { |
||
634 | $this->currentOrder()->write(); |
||
635 | $this->addMessage(_t('Order.ORDERSAVED', 'Order Saved.'), 'good'); |
||
636 | |||
637 | return true; |
||
638 | } |
||
639 | } |
||
640 | |||
641 | /** |
||
642 | * Clears the cart contents completely by removing the orderID from session, and |
||
643 | * thus creating a new cart on next request. |
||
644 | * |
||
645 | * @return bool |
||
646 | */ |
||
647 | public function clear() |
||
648 | { |
||
649 | //we keep this here so that a flush can be added... |
||
650 | set_time_limit(1 * 60); |
||
651 | self::$_singletoncart = null; |
||
652 | $this->order = null; |
||
653 | $this->messages = array(); |
||
654 | foreach (self::$session_variable_names as $name) { |
||
655 | $sessionVariableName = $this->sessionVariableName($name); |
||
656 | Session::set($sessionVariableName, null); |
||
657 | Session::clear($sessionVariableName); |
||
658 | Session::save(); |
||
659 | } |
||
660 | $memberID = Intval(Member::currentUserID()); |
||
661 | if ($memberID) { |
||
662 | $orders = Order::get()->filter(array('MemberID' => $memberID)); |
||
663 | if ($orders && $orders->count()) { |
||
664 | foreach ($orders as $order) { |
||
665 | if (! $order->IsSubmitted()) { |
||
666 | $order->delete(); |
||
667 | } |
||
668 | } |
||
669 | } |
||
670 | } |
||
671 | |||
672 | return true; |
||
673 | } |
||
674 | |||
675 | /** |
||
676 | * alias for clear. |
||
677 | */ |
||
678 | public function reset() |
||
679 | { |
||
680 | return $this->clear(); |
||
681 | } |
||
682 | |||
683 | /** |
||
684 | * Removes a modifier from the cart |
||
685 | * It does not actually remove it, but it just |
||
686 | * sets it as "removed", to avoid that it is being |
||
687 | * added again. |
||
688 | * |
||
689 | * returns null if the current user does not allow order manipulation or saving (e.g. session disabled) |
||
690 | * |
||
691 | * @param OrderModifier $modifier |
||
692 | * |
||
693 | * @return bool | null |
||
0 ignored issues
–
show
|
|||
694 | */ |
||
695 | public function removeModifier(OrderModifier $modifier) |
||
696 | { |
||
697 | if($this->allowWrites()) { |
||
698 | $modifier = (is_numeric($modifier)) ? OrderModifier::get()->byID($modifier) : $modifier; |
||
699 | if (!$modifier) { |
||
700 | $this->addMessage(_t('Order.MODIFIERNOTFOUND', 'Modifier could not be found.'), 'bad'); |
||
701 | |||
702 | return false; |
||
703 | } |
||
704 | if (!$modifier->CanBeRemoved()) { |
||
705 | $this->addMessage(_t('Order.MODIFIERCANNOTBEREMOVED', 'Modifier can not be removed.'), 'bad'); |
||
706 | |||
707 | return false; |
||
708 | } |
||
709 | $modifier->HasBeenRemoved = 1; |
||
710 | $modifier->onBeforeRemove(); |
||
711 | $modifier->write(); |
||
712 | $modifier->onAfterRemove(); |
||
713 | $this->addMessage(_t('Order.MODIFIERREMOVED', 'Removed.'), 'good'); |
||
714 | |||
715 | return true; |
||
716 | } |
||
717 | } |
||
718 | |||
719 | /** |
||
720 | * Removes a modifier from the cart. |
||
721 | * |
||
722 | * returns null if the current user does not allow order manipulation or saving (e.g. session disabled) |
||
723 | * |
||
724 | * @param Int/ OrderModifier |
||
725 | * |
||
726 | * @return bool |
||
0 ignored issues
–
show
|
|||
727 | */ |
||
728 | public function addModifier($modifier) |
||
729 | { |
||
730 | if($this->allowWrites()) { |
||
731 | if (is_numeric($modifier)) { |
||
732 | $modifier = OrderModifier::get()->byID($modifier); |
||
733 | } elseif (!(is_a($modifier, Object::getCustomClass('OrderModifier')))) { |
||
734 | user_error('Bad parameter provided to ShoppingCart::addModifier', E_USER_WARNING); |
||
735 | } |
||
736 | if (!$modifier) { |
||
737 | $this->addMessage(_t('Order.MODIFIERNOTFOUND', 'Modifier could not be found.'), 'bad'); |
||
738 | |||
739 | return false; |
||
740 | } |
||
741 | $modifier->HasBeenRemoved = 0; |
||
742 | $modifier->write(); |
||
743 | $this->addMessage(_t('Order.MODIFIERREMOVED', 'Added.'), 'good'); |
||
744 | |||
745 | return true; |
||
746 | } |
||
747 | } |
||
748 | |||
749 | /** |
||
750 | * Sets an order as the current order. |
||
751 | * |
||
752 | * @param int | Order $order |
||
753 | * |
||
754 | * @return bool |
||
755 | */ |
||
756 | public function loadOrder($order) |
||
757 | { |
||
758 | if($this->allowWrites()) { |
||
759 | //TODO: how to handle existing order |
||
760 | //TODO: permission check - does this belong to another member? ...or should permission be assumed already? |
||
761 | if (is_numeric($order)) { |
||
762 | $this->order = Order::get()->byID($order); |
||
763 | } elseif (is_a($order, Object::getCustomClass('Order'))) { |
||
764 | $this->order = $order; |
||
765 | } else { |
||
766 | user_error('Bad order provided as parameter to ShoppingCart::loadOrder()'); |
||
767 | } |
||
768 | if ($this->order) { |
||
769 | //first can view and then, if can view, set as session... |
||
770 | if ($this->order->canView()) { |
||
771 | $this->order->init(true); |
||
772 | $sessionVariableName = $this->sessionVariableName('OrderID'); |
||
773 | //we set session ID after can view check ... |
||
774 | Session::set($sessionVariableName, $this->order->ID); |
||
775 | $this->addMessage(_t('Order.LOADEDEXISTING', 'Order loaded.'), 'good'); |
||
776 | |||
777 | return true; |
||
778 | } else { |
||
779 | $this->addMessage(_t('Order.NOPERMISSION', 'You do not have permission to view this order.'), 'bad'); |
||
780 | |||
781 | return false; |
||
782 | } |
||
783 | } else { |
||
784 | $this->addMessage(_t('Order.NOORDER', 'Order can not be found.'), 'bad'); |
||
785 | |||
786 | return false; |
||
787 | } |
||
788 | } else { |
||
789 | $this->addMessage(_t('Order.NOSAVE', 'You can not load orders as your session functionality is turned off.'), 'bad'); |
||
790 | |||
791 | return false; |
||
792 | } |
||
793 | |||
794 | } |
||
795 | |||
796 | /** |
||
797 | * NOTE: tried to copy part to the Order Class - but that was not much of a go-er. |
||
798 | * |
||
799 | * returns null if the current user does not allow order manipulation or saving (e.g. session disabled) |
||
800 | * |
||
801 | * @param int | Order $order |
||
802 | * |
||
803 | * @return Order | false | null |
||
0 ignored issues
–
show
|
|||
804 | **/ |
||
805 | public function copyOrder($oldOrder) |
||
806 | { |
||
807 | if($this->allowWrites()) { |
||
808 | if (is_numeric($oldOrder)) { |
||
809 | $oldOrder = Order::get()->byID(intval($oldOrder)); |
||
810 | } elseif (is_a($oldOrder, Object::getCustomClass('Order'))) { |
||
811 | //$oldOrder = $oldOrder; |
||
812 | } else { |
||
813 | user_error('Bad order provided as parameter to ShoppingCart::loadOrder()'); |
||
814 | } |
||
815 | if ($oldOrder) { |
||
816 | if ($oldOrder->canView() && $oldOrder->IsSubmitted()) { |
||
817 | $newOrder = Order::create(); |
||
818 | //copying fields. |
||
819 | $newOrder->UseShippingAddress = $oldOrder->UseShippingAddress; |
||
0 ignored issues
–
show
The property
UseShippingAddress does not exist on object<Order> . Since you implemented __set , maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
820 | //important to set it this way... |
||
821 | $newOrder->setCurrency($oldOrder->CurrencyUsed()); |
||
822 | $newOrder->MemberID = $oldOrder->MemberID; |
||
0 ignored issues
–
show
The property
MemberID does not exist on object<Order> . Since you implemented __set , maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
823 | //load the order |
||
824 | $newOrder->write(); |
||
825 | $this->loadOrder($newOrder); |
||
826 | $items = OrderItem::get() |
||
827 | ->filter(array('OrderID' => $oldOrder->ID)); |
||
828 | if ($items->count()) { |
||
829 | foreach ($items as $item) { |
||
830 | $buyable = $item->Buyable($current = true); |
||
831 | if ($buyable->canPurchase()) { |
||
832 | $this->addBuyable($buyable, $item->Quantity); |
||
833 | } |
||
834 | } |
||
835 | } |
||
836 | $newOrder->CreateOrReturnExistingAddress('BillingAddress'); |
||
837 | $newOrder->CreateOrReturnExistingAddress('ShippingAddress'); |
||
838 | $newOrder->write(); |
||
839 | $this->addMessage(_t('Order.ORDERCOPIED', 'Order has been copied.'), 'good'); |
||
840 | |||
841 | return $newOrder; |
||
842 | } else { |
||
843 | $this->addMessage(_t('Order.NOPERMISSION', 'You do not have permission to view this order.'), 'bad'); |
||
844 | |||
845 | return false; |
||
846 | } |
||
847 | } else { |
||
848 | $this->addMessage(_t('Order.NOORDER', 'Order can not be found.'), 'bad'); |
||
849 | |||
850 | return false; |
||
851 | } |
||
852 | } |
||
853 | } |
||
854 | |||
855 | /** |
||
856 | * sets country in order so that modifiers can be recalculated, etc... |
||
857 | * |
||
858 | * @param string - $countryCode |
||
859 | * |
||
860 | * @return bool |
||
0 ignored issues
–
show
|
|||
861 | **/ |
||
862 | public function setCountry($countryCode) |
||
863 | { |
||
864 | if($this->allowWrites()) { |
||
865 | if (EcommerceCountry::code_allowed($countryCode)) { |
||
866 | $this->currentOrder()->SetCountryFields($countryCode); |
||
867 | $this->addMessage(_t('Order.UPDATEDCOUNTRY', 'Updated country.'), 'good'); |
||
868 | |||
869 | return true; |
||
870 | } else { |
||
871 | $this->addMessage(_t('Order.NOTUPDATEDCOUNTRY', 'Could not update country.'), 'bad'); |
||
872 | |||
873 | return false; |
||
874 | } |
||
875 | } |
||
876 | } |
||
877 | |||
878 | /** |
||
879 | * sets region in order so that modifiers can be recalculated, etc... |
||
880 | * |
||
881 | * @param int | String - $regionID you can use the ID or the code. |
||
882 | * |
||
883 | * @return bool |
||
884 | **/ |
||
885 | public function setRegion($regionID) |
||
886 | { |
||
887 | if (EcommerceRegion::regionid_allowed($regionID)) { |
||
888 | $this->currentOrder()->SetRegionFields($regionID); |
||
889 | $this->addMessage(_t('ShoppingCart.REGIONUPDATED', 'Region updated.'), 'good'); |
||
890 | |||
891 | return true; |
||
892 | } else { |
||
893 | $this->addMessage(_t('ORDER.NOTUPDATEDREGION', 'Could not update region.'), 'bad'); |
||
894 | |||
895 | return false; |
||
896 | } |
||
897 | } |
||
898 | |||
899 | /** |
||
900 | * sets the display currency for the cart. |
||
901 | * |
||
902 | * @param string $currencyCode |
||
903 | * |
||
904 | * @return bool |
||
905 | **/ |
||
906 | public function setCurrency($currencyCode) |
||
907 | { |
||
908 | $currency = EcommerceCurrency::get_one_from_code($currencyCode); |
||
909 | if ($currency) { |
||
910 | if ($this->currentOrder()->MemberID) { |
||
0 ignored issues
–
show
The property
MemberID does not exist on object<Order> . 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.
Loading history...
|
|||
911 | $member = $this->currentOrder()->Member(); |
||
912 | if ($member && $member->exists()) { |
||
913 | $member->SetPreferredCurrency($currency); |
||
914 | } |
||
915 | } |
||
916 | $this->currentOrder()->UpdateCurrency($currency); |
||
917 | $msg = _t('Order.CURRENCYUPDATED', 'Currency updated.'); |
||
918 | $this->addMessage($msg, 'good'); |
||
919 | |||
920 | return true; |
||
921 | } else { |
||
922 | $msg = _t('Order.CURRENCYCOULDNOTBEUPDATED', 'Currency could not be updated.'); |
||
923 | $this->addMessage($msg, 'bad'); |
||
924 | |||
925 | return false; |
||
926 | } |
||
927 | } |
||
928 | |||
929 | /** |
||
930 | * Produces a debug of the shopping cart. |
||
931 | */ |
||
932 | public function debug() |
||
933 | { |
||
934 | if (Director::isDev() || Permission::check('ADMIN')) { |
||
935 | debug::show($this->currentOrder()); |
||
936 | |||
937 | echo '<hr /><hr /><hr /><hr /><hr /><hr /><h1>Country</h1>'; |
||
938 | echo 'GEOIP Country: '.EcommerceCountry::get_country_from_ip().'<br />'; |
||
939 | echo 'Calculated Country Country: '.EcommerceCountry::get_country().'<br />'; |
||
940 | |||
941 | echo '<blockquote><blockquote><blockquote><blockquote>'; |
||
942 | |||
943 | echo '<hr /><hr /><hr /><hr /><hr /><hr /><h1>Items</h1>'; |
||
944 | $items = $this->currentOrder()->Items(); |
||
945 | echo $items->sql(); |
||
946 | echo '<hr />'; |
||
947 | if ($items->count()) { |
||
948 | foreach ($items as $item) { |
||
949 | Debug::show($item); |
||
950 | } |
||
951 | } else { |
||
952 | echo '<p>there are no items for this order</p>'; |
||
953 | } |
||
954 | |||
955 | echo '<hr /><hr /><hr /><hr /><hr /><hr /><h1>Modifiers</h1>'; |
||
956 | $modifiers = $this->currentOrder()->Modifiers(); |
||
957 | if ($modifiers->count()) { |
||
958 | foreach ($modifiers as $modifier) { |
||
959 | Debug::show($modifier); |
||
960 | } |
||
961 | } else { |
||
962 | echo '<p>there are no modifiers for this order</p>'; |
||
963 | } |
||
964 | |||
965 | echo '<hr /><hr /><hr /><hr /><hr /><hr /><h1>Addresses</h1>'; |
||
966 | $billingAddress = $this->currentOrder()->BillingAddress(); |
||
967 | if ($billingAddress && $billingAddress->exists()) { |
||
968 | Debug::show($billingAddress); |
||
969 | } else { |
||
970 | echo '<p>there is no billing address for this order</p>'; |
||
971 | } |
||
972 | $shippingAddress = $this->currentOrder()->ShippingAddress(); |
||
973 | if ($shippingAddress && $shippingAddress->exists()) { |
||
974 | Debug::show($shippingAddress); |
||
975 | } else { |
||
976 | echo '<p>there is no shipping address for this order</p>'; |
||
977 | } |
||
978 | |||
979 | $currencyUsed = $this->currentOrder()->CurrencyUsed(); |
||
0 ignored issues
–
show
The method
CurrencyUsed does not exist on object<Order> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
Loading history...
|
|||
980 | if ($currencyUsed && $currencyUsed->exists()) { |
||
981 | echo '<hr /><hr /><hr /><hr /><hr /><hr /><h1>Currency</h1>'; |
||
982 | Debug::show($currencyUsed); |
||
983 | } |
||
984 | |||
985 | $cancelledBy = $this->currentOrder()->CancelledBy(); |
||
0 ignored issues
–
show
The method
CancelledBy does not exist on object<Order> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
Loading history...
|
|||
986 | if ($cancelledBy && $cancelledBy->exists()) { |
||
987 | echo '<hr /><hr /><hr /><hr /><hr /><hr /><h1>Cancelled By</h1>'; |
||
988 | Debug::show($cancelledBy); |
||
989 | } |
||
990 | |||
991 | $logs = $this->currentOrder()->OrderStatusLogs(); |
||
992 | if ($logs && $logs->count()) { |
||
993 | echo '<hr /><hr /><hr /><hr /><hr /><hr /><h1>Logs</h1>'; |
||
994 | foreach ($logs as $log) { |
||
995 | Debug::show($log); |
||
996 | } |
||
997 | } |
||
998 | |||
999 | $payments = $this->currentOrder()->Payments(); |
||
1000 | if ($payments && $payments->count()) { |
||
1001 | echo '<hr /><hr /><hr /><hr /><hr /><hr /><h1>Payments</h1>'; |
||
1002 | foreach ($payments as $payment) { |
||
1003 | Debug::show($payment); |
||
1004 | } |
||
1005 | } |
||
1006 | |||
1007 | $emails = $this->currentOrder()->Emails(); |
||
1008 | if ($emails && $emails->count()) { |
||
1009 | echo '<hr /><hr /><hr /><hr /><hr /><hr /><h1>Emails</h1>'; |
||
1010 | foreach ($emails as $email) { |
||
1011 | Debug::show($email); |
||
1012 | } |
||
1013 | } |
||
1014 | |||
1015 | echo '</blockquote></blockquote></blockquote></blockquote>'; |
||
1016 | } else { |
||
1017 | echo 'Please log in as admin first'; |
||
1018 | } |
||
1019 | } |
||
1020 | |||
1021 | /** |
||
1022 | * Stores a message that can later be returned via ajax or to $form->sessionMessage();. |
||
1023 | * |
||
1024 | * @param $message - the message, which could be a notification of successful action, or reason for failure |
||
1025 | * @param $type - please use good, bad, warning |
||
1026 | */ |
||
1027 | public function addMessage($message, $status = 'good') |
||
1028 | { |
||
1029 | //clean status for the lazy programmer |
||
1030 | //TODO: remove the awkward replace |
||
1031 | $status = strtolower($status); |
||
1032 | str_replace(array('success', 'failure'), array('good', 'bad'), $status); |
||
1033 | $statusOptions = array('good', 'bad', 'warning'); |
||
1034 | if (!in_array($status, $statusOptions)) { |
||
1035 | user_error('Message status should be one of the following: '.implode(',', $statusOptions), E_USER_NOTICE); |
||
1036 | } |
||
1037 | $this->messages[] = array( |
||
1038 | 'Message' => $message, |
||
1039 | 'Type' => $status, |
||
1040 | ); |
||
1041 | } |
||
1042 | |||
1043 | /******************************************************* |
||
1044 | * HELPER FUNCTIONS |
||
1045 | *******************************************************/ |
||
1046 | |||
1047 | /** |
||
1048 | * Gets an existing order item based on buyable and passed parameters. |
||
1049 | * |
||
1050 | * @param DataObject $buyable |
||
0 ignored issues
–
show
Should the type for parameter
$buyable not be BuyableModel ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
1051 | * @param array $parameters |
||
1052 | * |
||
1053 | * @return OrderItem | null |
||
0 ignored issues
–
show
|
|||
1054 | */ |
||
1055 | protected function getExistingItem(BuyableModel $buyable, array $parameters = array()) |
||
1056 | { |
||
1057 | $filterString = $this->parametersToSQL($parameters); |
||
1058 | if ($order = $this->currentOrder()) { |
||
1059 | $orderID = $order->ID; |
||
1060 | $obj = OrderItem::get() |
||
1061 | ->where( |
||
1062 | " \"BuyableClassName\" = '".$buyable->ClassName."' AND |
||
1063 | \"BuyableID\" = ".$buyable->ID.' AND |
||
1064 | "OrderID" = '.$orderID.' '. |
||
1065 | $filterString |
||
1066 | ) |
||
1067 | ->First(); |
||
1068 | |||
1069 | return $obj; |
||
1070 | } |
||
1071 | } |
||
1072 | |||
1073 | /** |
||
1074 | * Removes parameters that aren't in the default array, merges with default parameters, and converts raw2SQL. |
||
1075 | * |
||
1076 | * @param array $parameters |
||
1077 | * |
||
1078 | * @return cleaned array |
||
0 ignored issues
–
show
|
|||
1079 | */ |
||
1080 | protected function cleanParameters(array $params = array()) |
||
1081 | { |
||
1082 | $defaultParamFilters = EcommerceConfig::get('ShoppingCart', 'default_param_filters'); |
||
1083 | $newarray = array_merge(array(), $defaultParamFilters); //clone array |
||
1084 | if (!count($newarray)) { |
||
1085 | return array(); //no use for this if there are not parameters defined |
||
1086 | } |
||
1087 | foreach ($newarray as $field => $value) { |
||
1088 | if (isset($params[$field])) { |
||
1089 | $newarray[$field] = Convert::raw2sql($params[$field]); |
||
1090 | } |
||
1091 | } |
||
1092 | |||
1093 | return $newarray; |
||
1094 | } |
||
1095 | |||
1096 | /** |
||
1097 | * @param array $parameters |
||
1098 | * Converts parameter array to SQL query filter |
||
1099 | */ |
||
1100 | protected function parametersToSQL(array $parameters = array()) |
||
1101 | { |
||
1102 | $defaultParamFilters = EcommerceConfig::get('ShoppingCart', 'default_param_filters'); |
||
1103 | if (!count($defaultParamFilters)) { |
||
1104 | return ''; //no use for this if there are not parameters defined |
||
1105 | } |
||
1106 | $cleanedparams = $this->cleanParameters($parameters); |
||
1107 | $outputArray = array(); |
||
1108 | foreach ($cleanedparams as $field => $value) { |
||
1109 | $outputarray[$field] = '"'.$field.'" = '.$value; |
||
1110 | } |
||
1111 | if (count($outputArray)) { |
||
1112 | return implode(' AND ', $outputArray); |
||
1113 | } |
||
1114 | |||
1115 | return ''; |
||
1116 | } |
||
1117 | |||
1118 | /******************************************************* |
||
1119 | * UI MESSAGE HANDLING |
||
1120 | *******************************************************/ |
||
1121 | |||
1122 | /** |
||
1123 | * Retrieves all good, bad, and ugly messages that have been produced during the current request. |
||
1124 | * |
||
1125 | * @return array of messages |
||
1126 | */ |
||
1127 | public function getMessages() |
||
1128 | { |
||
1129 | $sessionVariableName = $this->sessionVariableName('Messages'); |
||
1130 | //get old messages |
||
1131 | $messages = unserialize(Session::get($sessionVariableName)); |
||
1132 | //clear old messages |
||
1133 | Session::clear($sessionVariableName, ''); |
||
1134 | //set to form???? |
||
1135 | if ($messages && count($messages)) { |
||
1136 | $this->messages = array_merge($messages, $this->messages); |
||
1137 | } |
||
1138 | |||
1139 | return $this->messages; |
||
1140 | } |
||
1141 | |||
1142 | /** |
||
1143 | *Saves current messages in session for retrieving them later. |
||
1144 | * |
||
1145 | *@return array of messages |
||
0 ignored issues
–
show
|
|||
1146 | */ |
||
1147 | protected function StoreMessagesInSession() |
||
1148 | { |
||
1149 | $sessionVariableName = $this->sessionVariableName('Messages'); |
||
1150 | Session::set($sessionVariableName, serialize($this->messages)); |
||
1151 | } |
||
1152 | |||
1153 | /** |
||
1154 | * This method is used to return data after an ajax call was made. |
||
1155 | * When a asynchronious request is made to the shopping cart (ajax), |
||
1156 | * then you will first action the request and then use this function |
||
1157 | * to return some values. |
||
1158 | * |
||
1159 | * It can also be used without ajax, in wich case it will redirects back |
||
1160 | * to the last page. |
||
1161 | * |
||
1162 | * Note that you can set the ajax response class in the configuration file. |
||
1163 | * |
||
1164 | * |
||
1165 | * @param string $message |
||
1166 | * @param string $status |
||
1167 | * @param Form $form |
||
0 ignored issues
–
show
Should the type for parameter
$form not be null|Form ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
1168 | * @returns String (JSON) |
||
1169 | */ |
||
1170 | public function setMessageAndReturn($message = '', $status = '', Form $form = 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
Loading history...
|
|||
1171 | { |
||
1172 | if ($message && $status) { |
||
1173 | $this->addMessage($message, $status); |
||
1174 | } |
||
1175 | //TODO: handle passing back multiple messages |
||
1176 | |||
1177 | if (Director::is_ajax()) { |
||
1178 | $responseClass = EcommerceConfig::get('ShoppingCart', 'response_class'); |
||
1179 | $obj = new $responseClass(); |
||
1180 | |||
1181 | return $obj->ReturnCartData($this->getMessages()); |
||
1182 | } else { |
||
1183 | //TODO: handle passing a message back to a form->sessionMessage |
||
1184 | $this->StoreMessagesInSession(); |
||
1185 | if ($form) { |
||
1186 | //lets make sure that there is an order |
||
1187 | $this->currentOrder(); |
||
1188 | //nowe we can (re)calculate the order |
||
1189 | $this->order->calculateOrderAttributes($force = false); |
||
1190 | $form->sessionMessage($message, $status); |
||
1191 | //let the form controller do the redirectback or whatever else is needed. |
||
1192 | } else { |
||
1193 | if (empty($_REQUEST['BackURL']) && Controller::has_curr()) { |
||
1194 | Controller::curr()->redirectBack(); |
||
1195 | } else { |
||
1196 | Controller::curr()->redirect(urldecode($_REQUEST['BackURL'])); |
||
1197 | } |
||
1198 | } |
||
1199 | |||
1200 | return; |
||
1201 | } |
||
1202 | } |
||
1203 | |||
1204 | /** |
||
1205 | * @return EcommerceDBConfig |
||
1206 | */ |
||
1207 | protected function EcomConfig() |
||
1208 | { |
||
1209 | return EcommerceDBConfig::current_ecommerce_db_config(); |
||
1210 | } |
||
1211 | |||
1212 | /** |
||
1213 | * Return the name of the session variable that should be used. |
||
1214 | * |
||
1215 | * @param string $name |
||
1216 | * |
||
1217 | * @return string |
||
1218 | */ |
||
1219 | protected function sessionVariableName($name = '') |
||
1220 | { |
||
1221 | if (!in_array($name, self::$session_variable_names)) { |
||
1222 | user_error("Tried to set session variable $name, that is not in use", E_USER_NOTICE); |
||
1223 | } |
||
1224 | $sessionCode = EcommerceConfig::get('ShoppingCart', 'session_code'); |
||
1225 | |||
1226 | return $sessionCode.'_'.$name; |
||
1227 | } |
||
1228 | } |
||
1229 |
This check looks for
@param
annotations where the type inferred by our type inference engine differs from the declared type.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.