Javascript-форум (https://javascript.ru/forum/)
-   Серверные языки и технологии (https://javascript.ru/forum/server/)
-   -   Вывод товара в корзине (https://javascript.ru/forum/server/55802-vyvod-tovara-v-korzine.html)

arhat78 15.05.2015 07:52

Вывод размера товара в корзине
 
Всем привет! В свободное от работы время изучаю PHP и тренируюсь в создании инет-магазина, и вот возник вопрос: добавляю в корзину ботинок Арт.10001 размер 20 из выпадающего списка, в корзине выводится этот ботинок с размером 20; затем добавляю в корзину этот же ботинок, но с размером 24 - а в корзине уже выводится этот последний ввод с размером 24, т.е размер 24 перезаписывает сверху размер 20. Вот как поменять код, какой применить принцип, чтобы в корзину добавлялся ботинок одного id, но с разными выбранными размерами? У размеров своя таблица в mysql, с id. Заранее благодарен.

Добавление товара в корзину:

<form action="index.php" method="get">
        <input type="hidden" name="view" value="add_to_cart">
        <input type="hidden" name="id" value="<?=$product['id']?>">
        <select name="size" >
        <?PHP
        $sql="SELECT * FROM sizes WHERE `sizes`.`id_boot`='$id' ";
        echo $sql.'<br>';
        $a=mysql_query($sql);
        while ($b = mysql_fetch_array($a))
        {
              echo "<option  value='$b[2]' >  $b[2] </option>";
        }
        ?>
        </select>
        <input type="submit" value="Добавить в корзину">
        </form>


Это вывод в корзине:

foreach ($_SESSION['cart'] as $id => $quantity): $product = get_product($id);
     
            $b['size'] = $_SESSION['cart_size'][$id];
     
            if (!empty($_GET['size'])) {echo $_GET['size'];}
          ?>
     
          <tr>
              <td align="center"><?=$product['title']; ?></td>
              <td align="center">  <?=$b['size'];?> </td>
              <td align="center">  <?=number_format($product['price'],2); ?> руб</td>
              <td align="center"><input type="text" size="2" name="<?=$id; ?>" maxlength="2" value="<?=$quantity; ?>" /></td>
              <td align="center">  <?=number_format($product['price'] * $quantity ,2); ?> руб</td>
          </tr>


И дальше коды связанные с добавлением в корзину:

case('add_to_cart'):
 $id = $_GET['id'];
 $size = $_GET['size'];
 
 $_SESSION['cart_size'][$id] = $size;
 
 $add_item = add_to_cart($id, $size);
 $_SESSION['total_items'] = total_items($_SESSION['cart']);
 $_SESSION['total_price'] = total_price($_SESSION['cart']);
 header('Location:index.php?view=product&id='.$id);
 break;


session_start();
 if(!isset($_SESSION['cart']))
 {
 $_SESSION['cart'] = array();
 $_SESSION['total_items'] = 0;
 $_SESSION['total_price'] = '0.00';
 }


function add_to_cart($id)
{
 if(isset($_SESSION['cart'][$id]))
 {
 $_SESSION['cart'][$id]++;
 return true;
 } 
 else
 {
 $_SESSION['cart'][$id] = 1;
 return true;
 }
 return false;
}

laimas 15.05.2015 09:14

Нужно менять представление корзины в сессии.

arhat78 15.05.2015 09:18

laimas, а не могли бы по подробнее??? А то так мне не понятно совсем...

laimas 15.05.2015 09:30

Почитайте тут. Не обязательно Ajax, можно и без него. Там описана корзина, ее возможная структура и почему такая выбрана.

arhat78 15.05.2015 13:54

laimas, что то подобное я уже встречал, но как это применить к моей корзине - так и не понял.

laimas 15.05.2015 14:16

Меняйте "свою" корзину, ее представление неудачное, почему, это по ссылке можно понять. Как вложить в вас "понимание", этого я не знаю. )

arhat78 15.05.2015 23:35

Цитата:

Сообщение от laimas (Сообщение 370976)
Меняйте "свою" корзину, ее представление неудачное, почему, это по ссылке можно понять. Как вложить в вас "понимание", этого я не знаю. )

Но нужно же понять, что именно не правильно, и как грамотно нужно поменять этот код. Я же только учусь, и очень тяжело "расшифровать" ваш код и понять, как его применить в моём случае.... Надеюсь, подскажете в каком направлении и как двигаться :thanks:

laimas 16.05.2015 06:54

Я же только учусь, и очень тяжело "расшифровать" ваш код и понять

А вы хотите чтобы я писал код так же как вы? :) Ну понятно, что так:

$_SESSION['total_items'] = total_items($_SESSION['cart']);
$_SESSION['total_price'] = total_price($_SESSION['cart']);

я делать не стану, и вот почему. Для программирования необходимо наличие логического мышления, но и не менее полезно уметь абстрагироваться от конкретных конструкций языка программирования. Можно даже сказать так - умение видеть задачу от общего к частному, это первично, а умение воплотить ее в конструкциях языка программирования, это уже вторично. Можно вызубрить наизусть все функции и конструкции языка, но так и не уметь написать что либо стоящее. А вот хорошее представление задачи как раз и позволяет выбрать необходимые инструменты в языке программирования для ее решения.

С какой целью у вас количество товаров в корзине и общая их сумма присваивается двум отдельным переменным - $_SESSION['total_items'] и $_SESSION['total_price']? Это только кажется, что так будет удобно и выгодно, а на самом деле это избыток данных не несущих каких либо преимуществ.

Представьте, что вы работаете в почтовом отделении и выполняете простую работу - нужно лизнуть марку и наклеить ее на конверт. Конверты с марками складывать отдельно. Изначально было выдано 1000 марок и 1000 конвертов. В конце рабочего дня нужно определить сколько осталось марок и конвертов осталось и запомнить. Не сложно, пересчитав конверты с марками, вычитаем это из 1000, получая нужное.

Если код вашей корзину переложить на работу в почтовом отделении, то получается, что вы работали так - марки лежали в одном столе, конверты в другом, а конверты с наклеенными марками вообще относились в другую комнату. При этом нужно было взять марку в одном столе, лизнуть ее, пойти к другому столу, взять конверт, наклеить марку и бежать в другую комнату.

Покупая в магазине товар, вы в уме будет считать общую их сумму, чтобы ориентироваться хватит ли у вас денег в кошельке (скоро считать в уме не надо будет, упаковки снабдят RFID-метками, и дисплей на тележке будет отображать просчитанную автоматически сумму). Всегда можно заглянуть в тележку, что-то убрать из нее, вернув на прилавок, что-то другое добавить, в общем "редактирование". Кассир на кассе также будет проверять товары в тележке, и только после того как товар оплачен, тележка будет пуста.

На все время пока совершалась покупка - от выбора товара на прилавке, до оплаты товаров на кассе, всегда требовалась тележка, то есть, перекладывая это на язык на программирование можно сказать, что на всем этапе использовали один и тот же объект - корзину. На основе содержимого тележки можно всегда знать и характеристики товара, и их количество, и их цену, и общую сумму.

А если представить, что вам "помогают" в покупке сестра и брат - сестра считает и записывает сумму за товары, но находится в отделе косметики, а брат катает тележку, но хочет приобрести перфоратор как месть перфоратору соседа и находится в отделе электрических товаров, а вы бегаете из продуктового отдела с товарами к ним, чтобы положить товар в тележку и узнать сколько же набрано. Понятное дело, что это помощь в кавычках, и сестра с братом лишние звенья.

Ваш код как раз и есть покупка с "помощью" сестры и брата. )

Как и в реальном магазине, так и в виртуальном, корзина требуется на всем этапе приобретения товара - от выбора его, до оформления заказа. Корзина должна быть единственным объектом хранящем все данные о товарах, и на основе которых можно получать те или иные параметры корзины. Разбрасывать эти параметры по другим переменным, это распылять внимание и писать лишний код.

По ссылке описано представление корзины, которое в вашем случае можно описать так:
$_SESSION['cart'] = array(
   209 => array(
      'count' => 3,
      'price'  => 1500,
      array('size'=>array(42 => 2, 41 => 1), 'name' => 'Галоши')
   ),
   150 => array(
      'count' => 2,
      'price'  => 1000,
      array('size'=>array(40 => 1, 41 => 1), 'name' => 'Туфли')
   )
);

где 209 и 150, это уникальные идентификаторы товаров, первичный ключ в sql-таблице. Именно он, а не Арт.1001 или иной. Артикулы, это информация для продавцов и, если надо, то и покупателю. Ключ count - хранит количество набранного товара, price - его цену за 1 шт., а в массиве хранится детализация о выборе - название товара и размер как ключ, значением которого будет количество набранного для его покупки. Если Галош выбрали 2 шт. 42-го размера и 1 шт. 41-го, то count равен 3.

Добавляя товар в корзину, нужно помещать его в корзину под его идентификатором, как ключом массива, а в массив детализации помещать размер как ключ, а выбранное количество размера как значение (нельзя запрещать покупать 42 размер в количестве более штуки). Если 42 размер уже был помещен в корзину в количестве 1 шт., а покупатель изменит количество на 2 или иное, то ключ 42 будет переписан с новым значением. Если покупатель выберет 0, или "удаление" 42-го размера, значит 0 он и есть 0, или удаляем.
При всех таких изменениях суммируется значение ключа count.

Узнать же всего товаров в корзине и сумму за них позволяют стандартные функции PHP - current, array_product, array_sum, array_map в функции totalBasket(), которая описана по ссылке на корзину.

А для полного представления корзины уже нужно будет обходить корзину циклом выводя ее подробное описание в удобном для представления виде.

arhat78 16.05.2015 10:17

laimas, сразу возникают вопросы. Например, до этого я вытаскивал данные о товаре в цикле из БД, а теперь, если применить этот код

$products = [23 => ['price'=>120, 'name'=>'Товар 1'], 245 => ['price'=>230, 'name'=>'Товар 2'], 39 => ['price'=>150, 'name'=>'Товар 3'], 109 => ['price'=>380, 'name'=>'Товар 4']];
, то получается мне нужно так заполнить переменную $products на 1000 строчек, да ещё каждый раз в ручную редактировать изменения в товаре...... То же самое касается и этого кода:
$_SESSION['cart'] = array(
	   209 => array(
	      'count' => 3,
	      'price'  => 1500,
	      array('size'=>array(42 => 2, 41 => 1), 'name' => 'Галоши')
	   ),

	   150 => array(
	      'count' => 2,
	      'price'  => 1000,
	      array('size'=>array(40 => 1, 41 => 1), 'name' => 'Туфли')
	   )
	);


Я уже встречал примерно такое построение, но как это применить на практике - примеров не встретил...

laimas 16.05.2015 15:12

Вытаскивать данные из базы в цикле, это очень и очень плохо, и означает насиловать базу. Об этом методе нужно забыть сразу.

Я забыл добавить ключ массиву характеристик в корзине товаров, сделаем это, и пусть на текущий момент корзина, и имеет указанные товары:
$_SESSION['cart'] = array(
       209 => array(
          'count' => 3,
          'price'  => 1500,
          'prop' => array('size'=>array(42 => 2, 41 => 1), 'name' => 'Галоши')
       ),
 
       150 => array(
          'count' => 2,
          'price'  => 1000,
          'prop' => array('size'=>array(40 => 1, 41 => 1), 'name' => 'Туфли')
       )
);

Если на страницах покупатель может выбрать количество товара, а также указывать его характеристики, в данном случае размер, то на сервер нужно отправлять массив описывающий такой выбор, в котором под первичным ключом хранится размер/размеры и набранное их количество. Допустим сервер получит заказ на новые товары, а также изменение количества товара ID209 для 41-го размера, и добавления 43-го размера с количеством 1 шт., и передается как $_POST['order'].

Первоочередной задачей будет определить не туфту ли прислали в первичных ключах, обезопасить их для подстановки в запрос, а также определение тех товаров, которых еще нет в корзине, чтобы обратиться к базе для получения их наименования и цены, и уже потом добавить их в базу. А также вычленить товар, который уже есть в корзине, чтобы обновить его параметры.

Вы читали о функция, ссылки на которые я дал? Даю еще на на семь, которые потребуются для решения выше указанных задач. Более ссылок я давать не буду, скачивайте руководство РНР, оно есть на русском, в удобном CHM формате, с примерами к функциям. Изучайте, уясняйте, тем более, что тип данных array, это тип с которым придется сталкиваться постоянно. А ковыряться в этом типе исключительно как for, foreach и т.п., это плодить многоэтажный код, в котором легко и заблудиться.

И так, нам потребуется встроенные РНР функции - intval, implode, array_diff, array_diff_key, array_intersect_key, array_keys, array_flip.

Обрабатываем полученный массив выбрасывая из него "пустышки" если такие есть, и если после этого вернется не пустой массив $order, то выполняем операции с корзиной:
if($order = array_intersect_key($_POST['order'], array_flip(array_diff(array_map('intval', array_keys($_POST['order'])), array(0))))) {
    //работаем с корзиной
}

Допустим в результате получим такой массив:
Array (
    [209] => Array (
            [42] => 3
            [43] => 1
        )
    [186] => Array  (
            [37] => 1
        )
    [254] => Array (
            [40] => 2
        )
)

В нем два новых товара ID186 и ID254. Нужно из массива $order получить эти идентификаторы и получить информацию о них из базы, но не двумя запросами в цикле, а одним запросом используя sql-оператор IN(). Если в таблице поле идентификаторов имеет имя id, то запрос будет типа такого:
$basket = &$_SESSION['cart']; //что такое ссылки, читать в руководстве
$sql = 'SELECT id, name, price FROM table_name WHERE id IN('.implode(',', array_keys(array_diff_key($order, $basket))).')';

В итоге будет сделан всего один запрос к базе и возвращены данные о товарах ID186 и ID254. После этого их можно добавлять в корзину. Товары параметры которых в корзине нужно обновить получаются так:
$upd = array_intersect_key($basket, $order);

А теперь попробуйте сами, зная (желательно бы знать) о функции array_sum(), решить задачу обновления и добавления в массиве корзины.

Нужно учиться на более простых примерах, а не хвататься сразу за написание магазинов. Я не стану укорять за написание магазина вами так - а работает и ладно, а на чем не важно. Но я и не стану вам помогать писать код в том ключе, как это вы делаете, мне это просто не интересно. И объяснять все детали подробно почему это у меня так, а не как у вас, я не буду. На данный момент я не располагаю временем, я и так написал более, чем следовало бы.


Часовой пояс GMT +3, время: 11:02.