05.03.2015, 06:11
|
Профессор
|
|
Регистрация: 14.01.2015
Сообщений: 12,989
|
|
<?
session_start();
//база товаров
$products = [
23 => ['price'=>120, 'name'=>'Товар 1'], 245 => ['price'=>230, 'name'=>'Товар 2'], 39 => ['price'=>150, 'name'=>'Товар 3'], 109 => ['price'=>380, 'name'=>'Товар 4']
];
//запрос на добавление товара
if($_POST) {
if($pid = (int)key(current($_POST)) AND $val = (int)$_POST['pid'][$pid]) { //что нам шлют?
//sleep(1); //убрать комментарий для проверки корректности действий на клиенте под локальным сервером
//проверяем есть ли такой товар в базе и, если требуется, то и наличе его на складе
if(array_key_exists($pid, $products)) {
//добавляем товар в корзину
$_SESSION['basket'][$pid] = [$val, $products[$pid]['price'], [$products[$pid]['name']]];
//получаем и возвращаем всего в корзине
exit(json_encode(totalBasket()));
} else exit(json_encode(['msg'=>'Нет в наличии']));
} else exit;
}
function totalBasket() {
$cart = &$_SESSION['basket'];
return [array_sum(array_map('current', $cart)), array_sum(array_map('array_product', $cart))];
}
?>
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>
#short-basket {
width: 700px;
height: 50px;
line-height: 50px;
padding-left: 10px;
background: #eee;
margin: 0 auto;
}
#products {
list-style: none;
padding: 0;
width: 700px;
margin: 20px auto;
}
#products li {
display: inline-block;
width: 300px;
vertical-align: top;
margin: 0 30px 50px 0;
}
#products li input {
width: 60px;
}
button {
padding: 2px 10px 2px 20px;
border: 0;
border-radius: 2px;
background: #ddd url(data:image/gif;base64,R0lGODlhCgAKAIAAAAD/AAAAACH5BAAAAAAALAAAAAAKAAoAAAIIhI+py+0PYysAOw==) no-repeat 5px 50%;
cursor: pointer;
}
.send {
background-image: url(data:image/gif;base64,R0lGODlhCgAKAIAAAP8AAAAAACH5BAAAAAAALAAAAAAKAAoAAAIIhI+py+0PYysAOw==);
}
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>
var add;
function toBasket(o) {
$.post(location, o.attr('name')+'='+o.val(), function(d) {
if(d.msg) {
alert(d.msg) //нет в наличии
} else {
//отображаем состояние корзины
$('#short-basket').find('b')
.eq(0)
.text(d[0]) //товаров
.end()
.eq(1)
.text(d[1]+'.00'); //на сумму
}
//удаляем анимацию у кнопки
o.next().removeClass('send');
//снимаем блокировку
add.prop('disabled', 0)
}, 'json')
}
$(function() {
add = $('#products').find('button');
add.click(function() {
//блокируем отправку
add.prop('disabled', 1)
toBasket($(this).addClass('send').prev())
});
});
</script>
</head>
<body>
<div id="short-basket">В корзине: товаров <b>0</b>, на сумму <b>0.00</b> руб.</div>
<ul id="products">
<?
foreach($products as $k=>$v) $ul .= '<li><h4>'.$v['name'].'</h4><p>Цена: '.$v['price'].'.00 руб.</p><input type="number" name="pid['.$k.']" value="1" min="1"> <button>В корзину</button></li>';
echo $ul;
?>
</ul>
</body>
</html>
Кнопки вывел за форму
Нет, имеется ввиду, что форма в данном случае не нужна, используются одни элементы INPUT, главное чтобы INPUT и BUTTON были обязательно соседними элементами братьями. Если же со страницы можно добавлять в корзину сразу несколько товаров, то в этом случае удобнее было бы использовать форму, ее событие onsubmit. При этом кнопка "В корзину" будет одна, а серверу будет отправляться массив N-товаров.
Прописал строку «Номер: (int)key($_POST['pid'])»
Это моя ошибка, таким образом можно и не получить, нужно как в примере выше. Сохраните его как .php под любым именем - адрес запроса указан как текущий посредством location, поэтому имя скрипта роли не играет.
Корзина на сессии, а так как время ее жизни является глобальной установкой, нельзя под каждого юзверя установить, то чтобы продлевать ее, можно периодически, например через 10 мин., опрашивать сервер асинхронным запросом без ответа. В этом случае использовать методы ajaxStart и ajaxStop нельзя, так как запросы для сессии и добавления товаров асинхронные, поэтому блокировка и снятие блокировки кнопок перенесено в инициализацию и финиш запроса добавления товаров соответственно.
Структура корзины следующая:
array(
ID_товара => array(
количество_товара,
цена_товара,
array(наименование_товара)
)
)
В этом случае легко просчитать общее количество товаров в корзине и их общую сумму стандартными функциями РНР. Именование товара, а возможно и другие какие либо его параметры дополнительные, помещаются в корзину для того, чтобы не "дергать" постоянно базу при обращении к корзине. Все эти доп. параметры должны быть помещены в массив, иначе использовать функцию array_product() для получения произведения количества на цену будет нельзя. Заполненный же массив будет возвращать для этой функции 1, что не будет влиять на результат умножения.
Пример написан под РНР не ниже 5.4.
Последний раз редактировалось laimas, 05.03.2015 в 07:51.
|
|
05.03.2015, 22:47
|
Интересующийся
|
|
Регистрация: 06.02.2013
Сообщений: 19
|
|
Сообщение от laimas
|
Пример написан под РНР не ниже 5.4.
|
Спасибо большое за полный развернутый код. Вы очень понятно и здорово все пишите. У меня правда возникла ошибка. Вставил в файл.php Ваш код. Все красиво работает, но добавляет товары в корзину по непонятному алгоритму. Если запустить страницу первый раз, то добавит нужное количество по нажатию одной из кнопок, суммируя все 4 input. Зато если повторить или задать другое число в одном из input и снова нажать button, то в корзину падает совершенно непонятное количество и сумма. Пытался как-то привести к общему знаменателю и понять в связи с чем такой подсчет, но решения не нашел. Может уделите еще немного своего драгоценного времени и поможете отладить код? Спасибо. Вам большое.
На скрине видно, что я добавил в 4 input число 10, результат корзина выдала совершенно неожиданный.
Последний раз редактировалось Aggao, 05.03.2015 в 22:50.
|
|
05.03.2015, 23:05
|
Профессор
|
|
Регистрация: 14.01.2015
Сообщений: 12,989
|
|
Вы думаете это ошибка и непонятный алгоритм?
Нет тут ошибки и непонятно. Если к примеру добавить первого товара 2 шт., а второго 3 шт., то общее количество будет равно 5 на сумму 930. Посмотрим что у нас в массиве корзины:
<pre>
print_r($_SESSION['basket']);
</pre>
и получаем:
Код:
|
Array
(
[23] => Array
(
[count] => 2
[price] => 120
[prop] => Array
(
[name] => Товар 1
)
)
[245] => Array
(
[count] => 3
[price] => 230
[prop] => Array
(
[name] => Товар 2
)
)
) |
Вопрос - если теперь изменить количество второго товара на 2, и вновь отправить его на севере, то какое состояние после этого будет у корзины? Ну наверное же ключ 245 корзины будет перезаписан, и общее число товаров будет равно 4, или не так? Так. А что это означает?
Измените части кода на следующие (думаю понятно будет что и где):
//запрос на добавление товара
if($_POST) {
if($pid = (int)key(current($_POST)) AND $val = (int)$_POST['pid'][$pid]) { //что нам шлют?
sleep(1); //убрать комментарий для проверки корректности действий на клиенте под локальным сервером
//проверяем есть ли такой товар в базе и, если требуется, то и наличе его на складе
if(array_key_exists($pid, $products)) {
//добваляем товар в корзину
$_SESSION['basket'][$pid] = ['count'=>$val, 'price'=>$products[$pid]['price'], 'prop'=>['name'=>$products[$pid]['name']]];
//получаем и возвращаем всего в корзине
exit(json_encode(totalBasket()));
} else exit(json_encode(['msg'=>'Нет в наличии']));
} else exit;
}
function totalBasket() {
return $_SESSION['basket'] ? [array_sum(array_map('current', $_SESSION['basket'])), array_sum(array_map('array_product', $_SESSION['basket']))] : [0, 0];
}
$tot = totalBasket();
//....
<div id="short-basket">В корзине: товаров <b><?=$tot[0]?></b>, на сумму <b><?=$tot[1]?>.00</b> руб.</div>
//........
foreach($products as $k=>$v) $ul .= '<li><h4>'.$v['name'].'</h4><p>Цена: '.$v['price'].'.00 руб.</p>'.
($_SESSION['basket'] && array_key_exists($k, $_SESSION['basket'])
? '<p>В корзине '.$_SESSION['basket'][$k]['count'].' шт.</p>'
: '<input type="number" name="pid['.$k.']" value="1" min="1"> <button>В корзину</button></li>');
Добавьте в корзину каких либо два товара, после чего обновите странице по F5. О чем либо это говорит?
Последний раз редактировалось laimas, 05.03.2015 в 23:09.
|
|
05.03.2015, 23:57
|
Интересующийся
|
|
Регистрация: 06.02.2013
Сообщений: 19
|
|
Сообщение от laimas
|
Вы думаете это ошибка и непонятный алгоритм?
|
Вы были правы, не совсем разобрался с корзиной. Поставил отображение array корзины и увидел, что пока сессия жива, в корзину добавлялись мною через input наименования. В результате, при новом добавлении количества, я видел непонятный результат. Я поставил у каждого товара количество 1 и все встало на свои места (на фото видно) Сразу появились вопросы
1. Для чего нужен sleep (1)?
2. Как сделать кнопку reset корзины, она там не будет лишней.
3. При обновлении страницы корзина показывает количество 0, сумма 0. Хотя в array корзины товары есть в каком-то количестве. Как это исправить? Я еще не попробовал Ваш новый код. Возможно он это и исправляет, сейчас займусь им
Сообщение от laimas
|
Вопрос - если теперь изменить количество второго товара на 2, и вновь отправить его на севере, то какое состояние после этого будет у корзины? Ну наверное же ключ 245 корзины будет перезаписан, и общее число товаров будет равно 4, или не так? Так. А что это означает?
|
Вот тут тоже интересный момент. При повторном добавление количества в корзину, я на php делал проверку, если такой товар не добавлен в таблицу базы от данного пользователя (который привязан к сессии по id), тогда мы создаем товар для него и ставим туда количество полученное из input, а если товар уже есть в корзине этого пользователя, тогда суммируем его.
|
|
06.03.2015, 00:26
|
Профессор
|
|
Регистрация: 14.01.2015
Сообщений: 12,989
|
|
1. Для чего нужен sleep (1)?
Для того чтобы проверить работу кнопок (анимация, блокировка) на локальном сервере. Ведь на нем все будет работать влет, и глазом моргнуть не успеете. А sleep (1) это пауза в одну секунду перед выполнением скрипта, а значит и ответа сервера, чтобы удостовериться, а потом убрать это. На реальном же сервере у вас в любом случае будут задержки.
2. Как сделать кнопку reset корзины, она там не будет лишней.
Либо поместить ul (это в примере, у вас может быть и что-то иное) в форму и использовать ее стандартную кнопку reset, либо любую кнопку, и обработчик ее на jQuery, например:
<button id="reset">Сбросить</button>
//в стилях кнопок
button:not([id=reset]) { //...
//либо можно оформить под кнопку reset любой иной элемент, и не трогать стили кнопок
//код
$('#reset').click(function() {
$('#products').find('input').val(1);
})
При использовании формы и input type=reset, в случае, если потребуется работать с элементами input, не забывайте об этой кнопке.
3. При обновлении страницы корзина показывает количество 0, сумма 0. Хотя в array корзины товары есть в каком-то количестве. Как это исправить? Я еще не попробовал Ваш новый код. Возможно он это и исправляет, сейчас займусь им
Займитесь, именно исправления это и учитывают.
если такой товар не добавлен в таблицу базы от данного пользователя (который привязан к сессии по id), тогда мы создаем товар для него и ставим туда количество полученное из input, а если товар уже есть в корзине этого пользователя, тогда суммируем его.
Вот тут действительно интересно. Мой пример в первой его инкарнации, это не только добавление, но и редактирование корзины со страницы товаров. Я ведь не зря вопросы задавал. То есть, после того как товар добавился в корзину, можно добавить сообщение у товара "В корзине", а текст кнопки сменить с "В корзину" на "Изменить".
А в вашем случае "а если товар уже есть в корзине этого пользователя, тогда суммируем его" при каждом добавлении товара надо и сообщать, и сбрасывать значение поля ввода в единицу, иначе это будет не добавление, а бардак
Но это уже политика магазина, как вам надо так и делайте, я могу по этому поводу иметь свое мнение, которое не обязательно должно быть истиной.
Последний раз редактировалось laimas, 06.03.2015 в 00:43.
|
|
06.03.2015, 10:52
|
Интересующийся
|
|
Регистрация: 06.02.2013
Сообщений: 19
|
|
Сброс ресет не работает на jquery.
Если я правильно понимаю этот код, то первая строка запускает функцию при нажатии на кнопку reset, а функция обращается к id = products, где ищет все input и устанавливает для них параметр val в 1.
$('#reset').click(function() {
$('#products').find('input').val(1);
})
Вот этот val = 1 должен сбрасывать удалять товары из корзины полностью, т.е. проставить количество всех товаров в 0. Я попробовал просто удалить сессию и все сбрасывается, но это команда php, а как без перезагрузки реализовать? можно конечно через форму указать тип кнопки и так чистить, у меня так и чистится на данный момент корзина, но интересует именно переделка корзины с отсутствием перезагрузки страниц. Я еще вечером попробую разобраться в вашем коде, пока не все понятно, учусь еще на ваших примерах
|
|
06.03.2015, 11:45
|
Профессор
|
|
Регистрация: 14.01.2015
Сообщений: 12,989
|
|
Естественно, что этот код устанавливает значения по умолчанию (1) в полях ввода, а сервер не запрашивается при этом, и естественно корзина не удаляется. Это как пример реализации "очистить форму, которой нет". А добавлять запрос к серверу я не стал по двум соображениям (добавление в корзину асинхронное, это важно):
1) Представим, что я ваш покупатель, и на странице А купил три бублика, на странице Б 5 кило конфет к бубликам, на странице В пакетик чая, а потом подумал, да ну его нафик, съем и так, всухомятку. Жму на кнопку reset, предполагая, что таким образом удаляю чай из корзины. Представляете мой ужас, когда я вернувшись на страницу А, пойму что сегодня останусь голодным?
Дело хозяйское, но по моему эта кнопка для корзины, это вред. Корзина в примере, это не корзина как таковая, это ее краткое представление. Вы когда в магазине реальном покупаете что-то, ведь в уме считаете наличие суммы в кармане и хватит ли ее на покупки? Вот для этого и служит краткое представление корзины в интернет магазине.
Сама же корзина, ее полное представление, в котором можно удалять товар/товары, изменять их количество, или вообще очистить корзину, вызывается отдельно. Это можно реализовать также асинхронным запросом, то есть, к примеру, кнопка/ссылка в кратком представлении раскрывает панель полного представления корзины - редактируйте на здоровье.
2) Корзина, это всего лишь часть задачи - приобретения товара в магазине. А задача, это от выбора товара до оформления заказа. И эту задачу надо решать комплексно, так чтобы сервер и клиент не каждый сам по себе, а единое. Это идея, интерфейс обслуживающий эту идею, удобное представление данных, чтобы сценарии этого интерфейса были оптимальны. А вот взять к примеру мой пример по добавлению товара, а потом притулить к нему кнопку "Сбросить", нагрузив сервер этой задачей как отдельным запросом, так не пойдет.
Последний раз редактировалось laimas, 06.03.2015 в 12:01.
|
|
|
|