1 | <?php |
||
2 | /* Divine CMS - Open source CMS for widespread use. |
||
3 | Copyright (c) 2019 Mykola Burakov ([email protected]) |
||
4 | |||
5 | See SOURCE.txt for other and additional information. |
||
6 | |||
7 | This file is part of Divine CMS. |
||
8 | |||
9 | This program is free software: you can redistribute it and/or modify |
||
10 | it under the terms of the GNU General Public License as published by |
||
11 | the Free Software Foundation, either version 3 of the License, or |
||
12 | (at your option) any later version. |
||
13 | |||
14 | This program is distributed in the hope that it will be useful, |
||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
17 | GNU General Public License for more details. |
||
18 | |||
19 | You should have received a copy of the GNU General Public License |
||
20 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
||
21 | |||
22 | namespace Divine\Engine\Library; |
||
23 | |||
24 | class Cart |
||
25 | { |
||
26 | private $data = array(); |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
27 | |||
28 | public function __construct($registry) |
||
0 ignored issues
–
show
|
|||
29 | { |
||
30 | $this->config = $registry->get('config'); |
||
0 ignored issues
–
show
|
|||
31 | $this->customer = $registry->get('customer'); |
||
0 ignored issues
–
show
|
|||
32 | $this->session = $registry->get('session'); |
||
0 ignored issues
–
show
|
|||
33 | $this->db = $registry->get('db'); |
||
0 ignored issues
–
show
|
|||
34 | |||
35 | // Remove all the expired carts with no customer ID |
||
36 | $this->db->query(" |
||
37 | DELETE FROM cart |
||
38 | WHERE customer_id = '0' |
||
39 | AND date_added < DATE_SUB(NOW(), INTERVAL 1 DAY) |
||
40 | "); |
||
41 | |||
42 | if ($this->customer->getId()) { |
||
43 | // We want to change the session ID on all the old items in the customers cart |
||
44 | $this->db->query(" |
||
45 | UPDATE cart |
||
46 | SET session_id = '" . $this->db->escape($this->session->getSessionId()) . "' |
||
47 | WHERE customer_id = '" . (int) $this->customer->getId() . "' |
||
48 | "); |
||
49 | |||
50 | // Once the customer is logged in we want to update the customers cart |
||
51 | $cart_query = $this->db->query(" |
||
52 | SELECT * |
||
53 | FROM cart |
||
54 | WHERE customer_id = '0' |
||
55 | AND session_id = '" . $this->db->escape($this->session->getSessionId()) . "' |
||
56 | "); |
||
57 | |||
58 | foreach ($cart_query->rows as $cart) { |
||
59 | $this->db->query(" |
||
60 | DELETE FROM cart |
||
61 | WHERE cart_id = '" . (int) $cart['cart_id'] . "' |
||
62 | "); |
||
63 | |||
64 | // The advantage of using $this->add is that it will check if the products already exist and increaser the quantity if necessary. |
||
65 | $this->add($cart['product_id'], $cart['quantity'], json_decode($cart['option'])); |
||
66 | } |
||
67 | } |
||
68 | } |
||
69 | |||
70 | public function getProducts() |
||
71 | { |
||
72 | $product_data = array(); |
||
73 | |||
74 | $cart_query = $this->db->query(" |
||
75 | SELECT * |
||
76 | FROM cart |
||
77 | WHERE customer_id = '" . (int) $this->customer->getId() . "' |
||
78 | AND session_id = '" . $this->db->escape($this->session->getSessionId()) . "' |
||
79 | "); |
||
80 | |||
81 | foreach ($cart_query->rows as $cart) { |
||
82 | $stock = true; |
||
83 | |||
84 | $product_query = $this->db->query(" |
||
85 | SELECT * |
||
86 | FROM product p |
||
87 | LEFT JOIN product_description pd ON (p.product_id = pd.product_id) |
||
88 | WHERE p.product_id = '" . (int) $cart['product_id'] . "' |
||
89 | AND pd.language_id = '" . (int) $this->config->get('config_language_id') . "' |
||
90 | AND p.status = '1' |
||
91 | "); |
||
92 | |||
93 | if ($product_query->num_rows && ($cart['quantity'] > 0)) { |
||
94 | $option_price = 0; |
||
95 | $option_points = 0; |
||
96 | |||
97 | $option_data = array(); |
||
98 | |||
99 | foreach (json_decode($cart['option']) as $product_option_id => $value) { |
||
100 | $option_query = $this->db->query(" |
||
101 | SELECT po.product_option_id, po.option_id, od.name, o.type |
||
102 | FROM product_option po |
||
103 | LEFT JOIN `option` o ON (po.option_id = o.option_id) |
||
104 | LEFT JOIN option_description od ON (o.option_id = od.option_id) |
||
105 | WHERE po.product_option_id = '" . (int) $product_option_id . "' |
||
106 | AND po.product_id = '" . (int) $cart['product_id'] . "' |
||
107 | AND od.language_id = '" . (int) $this->config->get('config_language_id') . "' |
||
108 | "); |
||
109 | |||
110 | if ($option_query->num_rows) { |
||
111 | if ($option_query->row['type'] == 'select' || $option_query->row['type'] == 'radio') { |
||
112 | $option_value_query = $this->db->query(" |
||
113 | SELECT pov.option_value_id, ovd.name, pov.quantity, pov.subtract, pov.price, pov.price_prefix, pov.points, pov.points_prefix |
||
114 | FROM product_option_value pov |
||
115 | LEFT JOIN option_value ov ON (pov.option_value_id = ov.option_value_id) |
||
116 | LEFT JOIN option_value_description ovd ON (ov.option_value_id = ovd.option_value_id) |
||
117 | WHERE pov.product_option_value_id = '" . (int) $value . "' |
||
118 | AND pov.product_option_id = '" . (int) $product_option_id . "' |
||
119 | AND ovd.language_id = '" . (int) $this->config->get('config_language_id') . "' |
||
120 | "); |
||
121 | |||
122 | if ($option_value_query->num_rows) { |
||
123 | if ($option_value_query->row['price_prefix'] == '+') { |
||
124 | $option_price += $option_value_query->row['price']; |
||
125 | } elseif ($option_value_query->row['price_prefix'] == '-') { |
||
126 | $option_price -= $option_value_query->row['price']; |
||
127 | } |
||
128 | |||
129 | if ($option_value_query->row['points_prefix'] == '+') { |
||
130 | $option_points += $option_value_query->row['points']; |
||
131 | } elseif ($option_value_query->row['points_prefix'] == '-') { |
||
132 | $option_points -= $option_value_query->row['points']; |
||
133 | } |
||
134 | |||
135 | if ($option_value_query->row['subtract'] && (!$option_value_query->row['quantity'] || ($option_value_query->row['quantity'] < $cart['quantity']))) { |
||
136 | $stock = false; |
||
137 | } |
||
138 | |||
139 | $option_data[] = array( |
||
140 | 'product_option_id' => $product_option_id, |
||
141 | 'product_option_value_id' => $value, |
||
142 | 'option_id' => $option_query->row['option_id'], |
||
143 | 'option_value_id' => $option_value_query->row['option_value_id'], |
||
144 | 'name' => $option_query->row['name'], |
||
145 | 'value' => $option_value_query->row['name'], |
||
146 | 'type' => $option_query->row['type'], |
||
147 | 'quantity' => $option_value_query->row['quantity'], |
||
148 | 'subtract' => $option_value_query->row['subtract'], |
||
149 | 'price' => $option_value_query->row['price'], |
||
150 | 'price_prefix' => $option_value_query->row['price_prefix'], |
||
151 | 'points' => $option_value_query->row['points'], |
||
152 | 'points_prefix' => $option_value_query->row['points_prefix'] |
||
153 | ); |
||
154 | } |
||
155 | } elseif ($option_query->row['type'] == 'checkbox' && is_array($value)) { |
||
156 | foreach ($value as $product_option_value_id) { |
||
157 | $option_value_query = $this->db->query(" |
||
158 | SELECT pov.option_value_id, pov.quantity, pov.subtract, pov.price, pov.price_prefix, pov.points, pov.points_prefix, ovd.name |
||
159 | FROM product_option_value pov |
||
160 | LEFT JOIN option_value_description ovd ON (pov.option_value_id = ovd.option_value_id) |
||
161 | WHERE pov.product_option_value_id = '" . (int) $product_option_value_id . "' |
||
162 | AND pov.product_option_id = '" . (int) $product_option_id . "' |
||
163 | AND ovd.language_id = '" . (int) $this->config->get('config_language_id') . "' |
||
164 | "); |
||
165 | |||
166 | if ($option_value_query->num_rows) { |
||
167 | if ($option_value_query->row['price_prefix'] == '+') { |
||
168 | $option_price += $option_value_query->row['price']; |
||
169 | } elseif ($option_value_query->row['price_prefix'] == '-') { |
||
170 | $option_price -= $option_value_query->row['price']; |
||
171 | } |
||
172 | |||
173 | if ($option_value_query->row['points_prefix'] == '+') { |
||
174 | $option_points += $option_value_query->row['points']; |
||
175 | } elseif ($option_value_query->row['points_prefix'] == '-') { |
||
176 | $option_points -= $option_value_query->row['points']; |
||
177 | } |
||
178 | |||
179 | if ($option_value_query->row['subtract'] && (!$option_value_query->row['quantity'] || ($option_value_query->row['quantity'] < $cart['quantity']))) { |
||
180 | $stock = false; |
||
181 | } |
||
182 | |||
183 | $option_data[] = array( |
||
184 | 'product_option_id' => $product_option_id, |
||
185 | 'product_option_value_id' => $product_option_value_id, |
||
186 | 'option_id' => $option_query->row['option_id'], |
||
187 | 'option_value_id' => $option_value_query->row['option_value_id'], |
||
188 | 'name' => $option_query->row['name'], |
||
189 | 'value' => $option_value_query->row['name'], |
||
190 | 'type' => $option_query->row['type'], |
||
191 | 'quantity' => $option_value_query->row['quantity'], |
||
192 | 'subtract' => $option_value_query->row['subtract'], |
||
193 | 'price' => $option_value_query->row['price'], |
||
194 | 'price_prefix' => $option_value_query->row['price_prefix'], |
||
195 | 'points' => $option_value_query->row['points'], |
||
196 | 'points_prefix' => $option_value_query->row['points_prefix'] |
||
197 | ); |
||
198 | } |
||
199 | } |
||
200 | } elseif ($option_query->row['type'] == 'text' || $option_query->row['type'] == 'textarea' || $option_query->row['type'] == 'file' || $option_query->row['type'] == 'date' || $option_query->row['type'] == 'datetime' || $option_query->row['type'] == 'time') { |
||
201 | $option_data[] = array( |
||
202 | 'product_option_id' => $product_option_id, |
||
203 | 'product_option_value_id' => '', |
||
204 | 'option_id' => $option_query->row['option_id'], |
||
205 | 'option_value_id' => '', |
||
206 | 'name' => $option_query->row['name'], |
||
207 | 'value' => $value, |
||
208 | 'type' => $option_query->row['type'], |
||
209 | 'quantity' => '', |
||
210 | 'subtract' => '', |
||
211 | 'price' => '', |
||
212 | 'price_prefix' => '', |
||
213 | 'points' => '', |
||
214 | 'points_prefix' => '' |
||
215 | ); |
||
216 | } |
||
217 | } |
||
218 | } |
||
219 | |||
220 | $price = $product_query->row['price']; |
||
221 | |||
222 | // Product Discounts |
||
223 | $discount_quantity = 0; |
||
224 | |||
225 | foreach ($cart_query->rows as $cart_2) { |
||
226 | if ($cart_2['product_id'] == $cart['product_id']) { |
||
227 | $discount_quantity += $cart_2['quantity']; |
||
228 | } |
||
229 | } |
||
230 | |||
231 | $product_discount_query = $this->db->query(" |
||
232 | SELECT price |
||
233 | FROM product_discount |
||
234 | WHERE product_id = '" . (int) $cart['product_id'] . "' |
||
235 | AND customer_group_id = '" . (int) $this->config->get('config_customer_group_id') . "' |
||
236 | AND quantity <= '" . (int) $discount_quantity . "' |
||
237 | AND ((date_start = '2000-01-01' OR date_start < NOW()) |
||
238 | AND (date_end = '2000-01-01' OR date_end > NOW())) |
||
239 | ORDER BY quantity DESC, priority ASC, price ASC |
||
240 | LIMIT 1 |
||
241 | "); |
||
242 | |||
243 | if ($product_discount_query->num_rows) { |
||
244 | $price = $product_discount_query->row['price']; |
||
245 | } |
||
246 | |||
247 | // Product Specials |
||
248 | $product_special_query = $this->db->query(" |
||
249 | SELECT price |
||
250 | FROM product_special |
||
251 | WHERE product_id = '" . (int) $cart['product_id'] . "' |
||
252 | AND customer_group_id = '" . (int) $this->config->get('config_customer_group_id') . "' |
||
253 | AND ((date_start = '2000-01-01' OR date_start < NOW()) |
||
254 | AND (date_end = '2000-01-01' OR date_end > NOW())) |
||
255 | ORDER BY priority ASC, price ASC |
||
256 | LIMIT 1 |
||
257 | "); |
||
258 | |||
259 | if ($product_special_query->num_rows) { |
||
260 | $price = $product_special_query->row['price']; |
||
261 | } |
||
262 | |||
263 | // Reward Points |
||
264 | $product_reward_query = $this->db->query(" |
||
265 | SELECT points |
||
266 | FROM product_reward |
||
267 | WHERE product_id = '" . (int) $cart['product_id'] . "' |
||
268 | AND customer_group_id = '" . (int) $this->config->get('config_customer_group_id') . "' |
||
269 | "); |
||
270 | |||
271 | if ($product_reward_query->num_rows) { |
||
272 | $reward = $product_reward_query->row['points']; |
||
273 | } else { |
||
274 | $reward = 0; |
||
275 | } |
||
276 | |||
277 | // Downloads |
||
278 | $download_data = array(); |
||
279 | |||
280 | $download_query = $this->db->query(" |
||
281 | SELECT * |
||
282 | FROM product_to_download p2d |
||
283 | LEFT JOIN download d ON (p2d.download_id = d.download_id) |
||
284 | LEFT JOIN download_description dd ON (d.download_id = dd.download_id) |
||
285 | WHERE p2d.product_id = '" . (int) $cart['product_id'] . "' |
||
286 | AND dd.language_id = '" . (int) $this->config->get('config_language_id') . "' |
||
287 | "); |
||
288 | |||
289 | foreach ($download_query->rows as $download) { |
||
290 | $download_data[] = array( |
||
291 | 'download_id' => $download['download_id'], |
||
292 | 'name' => $download['name'], |
||
293 | 'filename' => $download['filename'], |
||
294 | 'mask' => $download['mask'] |
||
295 | ); |
||
296 | } |
||
297 | |||
298 | // Stock |
||
299 | if (!$product_query->row['quantity'] || ($product_query->row['quantity'] < $cart['quantity'])) { |
||
300 | $stock = false; |
||
301 | } |
||
302 | |||
303 | $product_data[] = array( |
||
304 | 'cart_id' => $cart['cart_id'], |
||
305 | 'product_id' => $product_query->row['product_id'], |
||
306 | 'name' => $product_query->row['name'], |
||
307 | 'model' => $product_query->row['model'], |
||
308 | 'shipping' => $product_query->row['shipping'], |
||
309 | 'image' => $product_query->row['image'], |
||
310 | 'option' => $option_data, |
||
311 | 'download' => $download_data, |
||
312 | 'quantity' => $cart['quantity'], |
||
313 | 'minimum' => $product_query->row['minimum'], |
||
314 | 'subtract' => $product_query->row['subtract'], |
||
315 | 'stock' => $stock, |
||
316 | 'price' => ($price + $option_price), |
||
317 | 'total' => ($price + $option_price) * $cart['quantity'], |
||
318 | 'reward' => $reward * $cart['quantity'], |
||
319 | 'points' => ($product_query->row['points'] ? ($product_query->row['points'] + $option_points) * $cart['quantity'] : 0), |
||
320 | 'width' => $product_query->row['width'], |
||
321 | 'height' => $product_query->row['height'] |
||
322 | ); |
||
323 | } else { |
||
324 | $this->remove($cart['cart_id']); |
||
325 | } |
||
326 | } |
||
327 | |||
328 | return $product_data; |
||
329 | } |
||
330 | |||
331 | public function add($product_id, $quantity = 1, $option = array()) |
||
332 | { |
||
333 | $query = $this->db->query(" |
||
334 | SELECT COUNT(*) AS total |
||
335 | FROM cart |
||
336 | WHERE customer_id = '" . (int) $this->customer->getId() . "' |
||
337 | AND session_id = '" . $this->db->escape($this->session->getSessionId()) . "' |
||
338 | AND product_id = '" . (int) $product_id . "' |
||
339 | AND `option` = '" . $this->db->escape(json_encode($option)) . "' |
||
340 | "); |
||
341 | |||
342 | if (!$query->row['total']) { |
||
343 | $this->db->query(" |
||
344 | INSERT cart |
||
345 | SET customer_id = '" . (int) $this->customer->getId() . "', |
||
346 | session_id = '" . $this->db->escape($this->session->getSessionId()) . "', |
||
347 | product_id = '" . (int) $product_id . "', |
||
348 | `option` = '" . $this->db->escape(json_encode($option)) . "', |
||
349 | quantity = '" . (int) $quantity . "', |
||
350 | date_added = NOW() |
||
351 | "); |
||
352 | } else { |
||
353 | $this->db->query(" |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
\n UPDATE...quantity = (quantity + does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||
354 | UPDATE cart |
||
355 | SET quantity = (quantity + " . (int) $quantity . ") |
||
356 | WHERE customer_id = '" . (int) $this->customer->getId() . "' |
||
357 | AND session_id = '" . $this->db->escape($this->session->getSessionId()) . "' |
||
358 | AND product_id = '" . (int) $product_id . "' |
||
359 | AND `option` = '" . $this->db->escape(json_encode($option)) . "' |
||
360 | "); |
||
361 | } |
||
362 | } |
||
363 | |||
364 | public function update($cart_id, $quantity) |
||
365 | { |
||
366 | $this->db->query(" |
||
367 | UPDATE cart |
||
368 | SET quantity = '" . (int) $quantity . "' |
||
369 | WHERE cart_id = '" . (int) $cart_id . "' |
||
370 | AND customer_id = '" . (int) $this->customer->getId() . "' |
||
371 | AND session_id = '" . $this->db->escape($this->session->getSessionId()) . "' |
||
372 | "); |
||
373 | } |
||
374 | |||
375 | public function remove($cart_id) |
||
376 | { |
||
377 | $this->db->query(" |
||
378 | DELETE FROM cart |
||
379 | WHERE cart_id = '" . (int) $cart_id . "' |
||
380 | AND customer_id = '" . (int) $this->customer->getId() . "' |
||
381 | AND session_id = '" . $this->db->escape($this->session->getSessionId()) . "' |
||
382 | "); |
||
383 | } |
||
384 | |||
385 | public function clear() |
||
386 | { |
||
387 | $this->db->query(" |
||
388 | DELETE FROM cart |
||
389 | WHERE customer_id = '" . (int) $this->customer->getId() . "' |
||
390 | AND session_id = '" . $this->db->escape($this->session->getSessionId()) . "' |
||
391 | "); |
||
392 | } |
||
393 | |||
394 | public function getSubTotal() |
||
395 | { |
||
396 | $total = 0; |
||
397 | |||
398 | foreach ($this->getProducts() as $product) { |
||
399 | $total += $product['total']; |
||
400 | } |
||
401 | |||
402 | return $total; |
||
403 | } |
||
404 | |||
405 | public function getTotal() |
||
406 | { |
||
407 | $total = 0; |
||
408 | |||
409 | foreach ($this->getProducts() as $product) { |
||
410 | $total += $product['price'] * $product['quantity']; |
||
411 | } |
||
412 | |||
413 | return $total; |
||
414 | } |
||
415 | |||
416 | public function countProducts() |
||
417 | { |
||
418 | $product_total = 0; |
||
419 | |||
420 | $products = $this->getProducts(); |
||
421 | |||
422 | foreach ($products as $product) { |
||
423 | $product_total += $product['quantity']; |
||
424 | } |
||
425 | |||
426 | return $product_total; |
||
427 | } |
||
428 | |||
429 | public function hasProducts() |
||
430 | { |
||
431 | return count($this->getProducts()); |
||
432 | } |
||
433 | |||
434 | public function hasStock() |
||
435 | { |
||
436 | foreach ($this->getProducts() as $product) { |
||
437 | if (!$product['stock']) { |
||
438 | return false; |
||
439 | } |
||
440 | } |
||
441 | |||
442 | return true; |
||
443 | } |
||
444 | |||
445 | public function hasShipping() |
||
446 | { |
||
447 | foreach ($this->getProducts() as $product) { |
||
448 | if ($product['shipping']) { |
||
449 | return true; |
||
450 | } |
||
451 | } |
||
452 | |||
453 | return false; |
||
454 | } |
||
455 | |||
456 | public function hasDownload() |
||
457 | { |
||
458 | foreach ($this->getProducts() as $product) { |
||
459 | if ($product['download']) { |
||
460 | return true; |
||
461 | } |
||
462 | } |
||
463 | |||
464 | return false; |
||
465 | } |
||
466 | } |
||
467 |