Welcome Guest, Not a member yet? Register   Sign In
Elegant Solution for Array Session - Ecommerce Basket
#1

[eluser]Yorkshire Pudding[/eluser]
Hi all,

I'm currently rebuilding one of my sites for the first time using Codeignitor.

My current basket code uses arrays saved in a session.

My old code looked like this
Code:
if (!isset($_SESSION['cart']))
    {
        $_SESSION['cart'] = array();
    }

    if (isset($_POST['productid']))
    {
        $_SESSION['cart'][] = $_POST['productid'];
        
    header('location: ' . $_SERVER['PHP_SELF'] . '?' . SID);
    exit();
    }

My new Codeignitor code looks like this:

Code:
if($this->input->post('product_id'))
            {
                if($this->session->userdata('cart'))
                {
                    if(!is_array($this->session->userdata('cart')))
                    {
                        $product_array = array();
                        $product_array[] = $this->session->userdata('cart');
                    }
                    else
                    {
                        $product_array = $this->session->userdata('cart');    
                    }
                    $product_array[] = $this->input->post('product_id');
                    $this->session->set_userdata('cart', $product_array);
                }
                else
                {
                    $this->session->set_userdata('cart', $this->input->post('product_id'));
                }    
            }

It works, but looks a bit bloated to me. Is there a more elegant way of doing this using Codeignitor?

Thanks for all you help in advance
#2

[eluser]flojon[/eluser]
If you always use an array for you cart userdata it will be easier. Something like this:
Code:
if($this->input->post('product_id'))
{
    if($this->session->userdata('cart'))
    {
        $product_array = $this->session->userdata('cart');
    }
    $product_array[] = $this->input->post('product_id');
    $this->session->set_userdata('cart', $product_array);
}
#3

[eluser]Yorkshire Pudding[/eluser]
Thanks for that. Have changed my basket to deal only with arrays and have adopted your solution. :-)
#4

[eluser]flojon[/eluser]
You're welcome! :-)
#5

[eluser]Dave Stewart[/eluser]
Something I just thought of (but haven't production-tested) would be to assign values to one variable by assigning a more-easily named by-reference pointer to it:

Code:
// start session
    session_start();
    
// create a short-named by-reference pointer to the long-winded-variable-name
// (note the & in front of the variable name)
    $username = &$_SESSION['user']['name'];
    
// assign the value to the variable via the referenced pointer
    if(!isset($username)){
        $username = 'Dave';
        }

// check the session variable
    echo "<pre>";
    print_r($_SESSION);
    echo "</pre>";

Not sure if that helps your problem or not, but it was interesting to play with anyway.
#6

[eluser]ontguy[/eluser]
This is what I've done, I'm not sure how elegant it is Smile

I haven't gone beyond the shopping cart as yet, so my approach may change.

Let me know what you think.

The cart holds a 2D array with the product id as the key:
Array ( [15] => Array ( [quantity] => 1 ) [6] => Array ( [quantity] => 1 ) [8] => Array ( [quantity] => 1 ) )

Only quantity is tracked but it's easy to add other details if needed.

Here is the jist of it:

application/libraries/Cart_lib.php
Code:
function get_cart()
{
  return $this->CI->session->userdata('cart');
}  

function set_cart($param)
{
  return $this->CI->session->set_userdata('cart', $param);
}

function add_item($product_id, $quantity = 1)
{
  $items = $this->get_cart();
  
  if (!$items)
  {
    $item = array($product_id => array(
                              'quantity' => $quantity,)
                              );

    $this->set_cart($item);
  }
  else
  {
    if (isset($items[$product_id]))
    {
      $items[$product_id]['quantity'] += $quantity;
    }
    else
    {
      $items += array($product_id => array(
                                  'quantity' => $quantity,)
                                  );
    }
    $this->set_cart($items);
  }
}

function edit_item($product_id = 0, $quantity = 0)
{
  if($quantity < 1)
  {
    $this->delete_item($product_id);
  }
  else
  {
    $items = $this->get_cart();
    
    $items[$product_id]['quantity'] = $quantity;

    $this->set_cart($items);
  }
}

function delete_item($item_id = 0)
{
  $items = $this->get_cart();
  $new_cart = array();
  
  foreach($items as $product_id => $product)
  {
    if($product_id != $item_id)
    {
      $new_cart += array($product_id => array(
                              'quantity' => $product['quantity'],)
                              );
    }
  }
  
  $this->set_cart($new_cart);
}
how the library is used in the controller:
application/controllers/cart.php
Code:
function view()
  {
    $this->data->cart = $this->cart_lib->cart_details();
  $this->data->total = $this->cart_lib->cart_total;

  $this->loadview('cart/view', $this->data);
}

function add()
  {
  $product_id = (int) $this->uri->segment(3);
  $this->cart_lib->add_item($product_id);
  
  redirect('catalog');
}

function delete()
{
    $product_id = (int) $this->uri->segment(3);

    if ($product_id != 0)
    {
    $this->cart_lib->delete_item($product_id);  

    redirect('cart/view');
  }
      else
      {
    $this->view();
  }
}

function update()
{
  foreach($_POST as $key => $value)
  {
    if (stristr($key,'quantity'))
    {
      $id = str_replace('quantity','',$key);

      if(preg_match( '/^[\-+]?[0-9]+$/', $value))
      {
        $this->cart_lib->edit_item($id, $value);        
      }
      else
      {
        $this->messages->add('The quantity field must contain an integer.', 'error');
      }
    }
  }
  
  redirect('cart/view');
}

the view would have something like this to utilize the cart controller:
application/views/catalog/browse.php
Code:
&lt;?=anchor('cart/add/'.$row->id, 'Add To Cart'); ?&gt;
#7

[eluser]Chris Williams[/eluser]
I'm check out this code. I'm curious if you need to put in CI in this code:

return $this->CI->session->userdata('cart');

Wouldn't it work without CI ->?
#8

[eluser]ontguy[/eluser]
It is needed since the CI session library is being used.

This is how the constructor is setup:
Code:
var $CI;

  function __construct()
  {
      $this->CI =& get_instance();
      log_message('debug', 'Cart class initialized.');
  }

In theory, if you were to use a session method other than the one provided with CI, just the function get_cart() and set_cart() would need be replaced and setup to return and receive the same format of data, and the rest should work.
#9

[eluser]Chris Williams[/eluser]
Sorry for the confusion, but I thought all I had to do was add session to the autoload library. Where would I insert the code you mention?
#10

[eluser]ontguy[/eluser]
In application/libraries/Cart_lib.php

Code:
class Cart_lib {
  var $CI;

  var $cart_total;
  
  function __construct()
  {
      $this->CI =& get_instance();
      log_message('debug', 'Cart class initialized.');
  }

//the other functions
}




Theme © iAndrew 2016 - Forum software by © MyBB