Показать сообщение отдельно
  #11 (permalink)  
Старый 05.03.2015, 06:11
Профессор
Отправить личное сообщение для laimas Посмотреть профиль Найти все сообщения от laimas
 
Регистрация: 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.
Ответить с цитированием