根据多个条件替换(或添加)多维关联数组

时间:2015-12-15 04:31:32

标签: php arrays multidimensional-array

我使用多维关联数组创建了一个购物车。可以添加新项目,并且已存在的项目的数量和总金额已更新。必须检查每件商品的装饰条件,并将具有独特条件的商品作为新商品添加到购物车中。

我编写了下面的代码,它确实有效,但似乎过于复杂。有没有更好的方法来完成这项工作?

// if there are items in the cart
if(isset($_SESSION['cart'])) {
    // loop through the array
    for($i = 0; $i <= count($_SESSION['cart']); $i++) {
        // if $name is found in $_SESSION['cart'] array ...
        if(in_array_r($name, $_SESSION['cart'])) {
            // if $i == count($_SESSION['cart']) that means a new item needs to be added since $name
            // was found in the array but no match for $condition was found 
            if($i == count($_SESSION['cart'])) {
                $_SESSION['cart'][] = array('name' => $name, 'condition' => $condition, 'quantity' => $quantity, 'itemTotal' => $itemTotal);
                break;
            }
            // if a match for $name and $condition is found update the quantity and totals for that item
            elseif($name == $_SESSION['cart'][$i]['name'] && $condition == $_SESSION['cart'][$i]['condition']) {
                $_SESSION['cart'][$i]['quantity'] = $_SESSION['cart'][$i]['quantity'] + $quantity;
                $_SESSION['cart'][$i]['itemTotal'] = $_SESSION['cart'][$i]['itemTotal'] + $itemTotal;
                break;
            }
            // continue through the loop to search for a match
            else {
                continue;
            }
        }
        // if $name isn't found in array add new item
        else {
            $_SESSION['cart'][] = array('name' => $name, 'condition' => $condition, 'quantity' => $quantity, 'itemTotal' => $itemTotal);
            break;  
        }
    }
    // sort in alphabetical order
    sort($_SESSION['cart']);
}
// if there are no items in the cart
else {
    $_SESSION['cart'][] = array('name' => $name, 'condition' => $condition, 'quantity' => $quantity, 'itemTotal' => $itemTotal);
}

// recursive in_array function
function in_array_r($needle, $haystack, $strict = false) {
foreach ($haystack as $item) {
    if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && in_array_r($needle, $item, $strict))) {
        return true;
    }
}
return false;

}

1 个答案:

答案 0 :(得分:1)

我建议您将您的卡片放入class,以便在整个网站范围内轻松编译和实施。这只是一个基本的例子,我不是建议使用它或替换你拥有的,看看它是否有任何价值,但它可能会给你一些想法:

<强> /classes/class.Cart.php

// Create an easy way to access your cart app
class   Cart
    {
        private static  $singleton;
        private static  $name;
        // Allows for same-resource re-use
        public  static function app()
            {
                self::$name =   (empty(self::$name))? 'cart' : self::$name;

                if(empty(self::$singleton))
                    self::$singleton    =   new ShoppingCart(self::$name);

                return self::$singleton;
            }

        public  static  function init($name = 'cart')
            {
                self::$name =   $name;
            }
    }

<强> /classes/class.ShoppingCart.php

class   ShoppingCart
    {
        public  $name;
        public  $condition;
        public  $total;
        public  $items;

        private $cart;
        private $cart_info;
        private $item;

        const   REV_SORT = 'r';
        const   NAT_SORT = 'n';
        // The construct will allow for using mulitple carts if required
        public  function __construct($name = 'cart')
            {
                $this->cName        =   $name;
                // This will save the cart data but it only holds the id and qty
                $this->cart         =   (!empty($_SESSION[$this->cName]))? $_SESSION[$this->cName] : array();
                // This will save a tandem session that only stores static data in reference to items added to the cart
                $this->cart_info    =   (!empty($_SESSION[$this->cName."_info"]))? $_SESSION[$this->cName."_info"] : array();
            }
        // This will retrieve a cart item's total value (qty x price)
        public  function getItemTotal($item = false)
            {
                if(empty($_SESSION[$this->cName][$item]))
                    return 0;
                // Filter all but numbers and decimals
                $price  =   (!empty($_SESSION[$this->cName."_info"][$item]['price']))? preg_replace('/[^0-9\.]/',"",$_SESSION[$this->cName.'_info'][$item]['price']) : false;
                // Check if qty is numeric, if not, just add qty as 1
                $qty    =   (!empty($_SESSION[$this->cName][$item]['qty']) && is_numeric($_SESSION[$this->cName][$item]['qty']))? $_SESSION[$this->cName][$item]['qty'] : 1;
                // Return the final price back. "invalid" means something was not submitted properly
                return (!empty($price))? ($_SESSION[$this->cName.'_info'][$item]['price'] * $qty) : 'invalid';
            }
        // This will fetch the total cart value
        public  function getCartTotal($format = false)
            {
                if(empty($_SESSION[$this->cName.'_info']))
                    return 0;
                // Save subtotals to new array
                foreach($_SESSION[$this->cName.'_info'] as $itm) {
                        $sub[]  =   $itm['subtotal'];
                    }
                // Sum the array
                $final  =   (!empty($sub))? array_sum($sub) : 0;
                // If the format is true, send back a currency value
                if($format) {
                        // This may draw error if on a WINDOWS machine.
                        // May have to use number_format() instead and possibly strpad()
                        setlocale(LC_MONETARY, 'en_US');
                        return money_format("%#10n",$final);
                    }
                // $format false will send back just the unformatted value
                else
                    return $final;
            }

        public  function getItemList($sort = 'n')
            {
                // Check if the session is set
                if(empty($_SESSION[$this->cName]))
                    return false;
                // Loop through the items and send back decoded names
                $arr    =   array_map(function($v) { return base64_decode($v); },array_keys($_SESSION[$this->cName]));
                // Check if there is a sort order specified
                switch($sort) {
                    case('n'):
                        // This may draw error if your PHP version is too low
                        asort($arr,SORT_NATURAL);
                        break;
                    case('r'):
                        arsort($arr);
                        break;
                    default:
                        sort($arr);
                }

                return $arr;
            }
        // This will return item details if it exists
        public  function getDetails($item = false)
            {
                $item   =   base64_encode($item);

                if(isset($_SESSION[$this->cName.'_info'][$item]))
                    return (object) $_SESSION[$this->cName.'_info'][$item];

                return false;
            }
        // This removes the details of a stored item
        public  function removeDetails()
            {
                if(isset($_SESSION[$this->cName.'_info'][$this->item])) {
                        unset($_SESSION[$this->cName.'_info'][$this->item]);
                        unset($this->cart_info[$this->item]);
                    }
            }
        // This sets the items calculated subtotal price (qty x price)
        public  function saveSubTotal()
            {
                return (!empty($_SESSION[$this->cName.'_info'][$this->item]['price']))? $this->getItemTotal($this->item) : 'invalid';
            }
        // This saves the items details. I use the $_GET details, but you can use data pulled from the DB or whatever
        public  function saveDetails($details = array())
            {
                if(isset($_SESSION[$this->cName][$this->item])) {
                        if(!isset($_SESSION[$this->cName.'_info'])) {
                                $this->cart_info    =   $_SESSION[$this->cName.'_info'] =   array();
                            }

                        $_SESSION[$this->cName.'_info'][$this->item]                =   $details;
                        $_SESSION[$this->cName.'_info'][$this->item]['subtotal']    =   $this->saveSubTotal();

                        $this->cart_info[$this->item]   =   $_SESSION[$this->cName.'_info'][$this->item];
                    }
            }
        // This adds to cart
        public  function addToCart($item = false, $qty = 1)
            {
                // It would be better just to use the id from your database, then it's unique and easy
                // but you are using name, so I am creating a generated id
                $this->item =   base64_encode($item);
                // Create cart
                if(!isset($_SESSION[$this->cName]))
                    $this->cart =   $_SESSION[$this->cName] =   array();
                // Add qty
                if(!isset($_SESSION[$this->cName][$this->item]))
                    $_SESSION[$this->cName][$this->item]['qty'] =   $qty;
                // or Update qty
                else
                    $_SESSION[$this->cName][$this->item]['qty'] +=  $qty;
                // Assign to a local variable
                $this->cart[$this->item]    =   $_SESSION[$this->cName][$this->item];
                // Return the object to use in method chaining
                return $this;
            }
        // This allows you to remove from the cart either by subtracting qty or by remove totally
        public  function removeFromCart($item = false,$amt = false)
            {
                $this->item =   base64_encode($item);
                if(!isset($_SESSION[$this->cName][$this->item]))
                    return;
                else {
                        if(is_numeric($amt)) {
                                $curr   =   (int) $_SESSION[$this->cName][$this->item]['qty'];
                                $amt    =   (int) $amt;
                                if(($curr - $amt) >= 0.01) {
                                        $this->cart_info[$this->item]['qty'] = $_SESSION[$this->cName][$this->item]['qty']  =   ($amt - $curr);
                                        $_SESSION[$this->cName.'_info'][$this->item]['subtotal']                            =   $this->saveSubTotal();
                                        return;
                                    }
                            }

                        unset($_SESSION[$this->cName][$this->item]);
                        unset($this->cart[$this->item]);
                        $this->removeDetails();
                    }
            }
        // Clear the entire cart
        public  function clearCart()
            {
                if(isset($_SESSION[$this->cName])) {
                        $this->cart         =   array();
                        $this->cart_info    =   array();
                        unset($_SESSION[$this->cName]);
                        unset($_SESSION[$this->cName."_info"]);
                    }
            }
        // Set the quantity based on validation of array parameter
        public  function setQty($array = false)
            {
                return ((!empty($array['qty']) && is_numeric($array['qty'])) && $array['qty'] !== 0)? $array['qty'] : 1;
            }
        // Set name based on parameter
        public  function setName($array = false)
            {
                return (!empty($array['name']))? $array['name'] : false;
            }
    }

<强>的index.php

// Include the above classes
include_once(__DIR__."/classes/class.Cart.php");
include_once(__DIR__."/classes/class.ShoppingCart.php");

// sets a the cart name, by default it's set to "cart"
// Cart::init("cart2");

// I am using $_GET, you can use $_POST if you want
// If add or remove
if(isset($_GET['add']) || isset($_GET['remove'])) {
        // Set defaults
        $qty    =   Cart::app()->setQty($_GET);
        $name   =   Cart::app()->setName($_GET);
        // If the name is empty, just stop
        if(empty($name))
            return false;
        // If adding, add to cart, save the item's details
        if(isset($_GET['add']))
            Cart::app()->addToCart($name,$qty)->saveDetails($_GET);
        // Else, you can remove
        // Leave second parameter blank if you want remove to just 
        // straight remove the item from cart
        // otherwise it will subtract if the $qty is numeric and not "false"
        else
            Cart::app()->removeFromCart($name,$qty);
    }
// Clear will remove the cart completely
// including the details
elseif(isset($_GET['clear']))
    Cart::app()->clearCart();

// get data for just the item 1
print_r(Cart::app()->getDetails("item1"));
// Get the list ordered naturally
print_r(Cart::app()->getItemList(ShoppingCart::NAT_SORT));
// Get the cart total
// Using true will format the output (see this method for more info if error occurs)
echo Cart::app()->getCartTotal(true);
// Show session
print_r($_SESSION);
?>
<a href="?add=true&name=item1&qty=1&condition=good&price=23.99">ADD ITEM1</a><br />
<a href="?add=true&name=item2&qty=1&condition=crap&price=24.50">ADD ITEM2</a><br />
<a href="?add=true&name=item3&qty=1&condition=horrible&price=34.50">ADD ITEM3</a><br />
<a href="?add=true&name=item4&qty=1&condition=super&price=11.33">ADD ITEM4</a><br />
<a href="?remove=true&name=item1">REMOVE ITEM1</a><br />
<a href="?remove=true&name=item2">REMOVE ITEM2</a><br />
<a href="?remove=true&name=item<?php echo $nm = rand(1,2); ?>&qty=10">REMOVE ITEM<?php echo $nm;?></a><br />
<a href="?remove=true&name=item<?php echo $nm = rand(3,4); ?>&qty=10">REMOVE ITEM<?php echo $nm;?></a><br />
<a href="?clear=true">Clear</a><br />

<强>输出:

// item1 details
stdClass Object
(
    [add] => true
    [name] => item1
    [qty] => 1
    [condition] => good
    [price] => 23.99
    [subtotal] => 23.99
)

// ordered list
Array
(
    [1] => item1
    [0] => item4
)

// Cart total
 $35.32

// cart session details
Array
(
    [cart] => Array
        (
            [aXRlbTQ=] => Array
                (
                    [qty] => 1
                )

            [aXRlbTE=] => Array
                (
                    [qty] => 1
                )
        )

    [cart_info] => Array
        (
            [aXRlbTQ=] => Array
                (
                    [add] => true
                    [name] => item4
                    [qty] => 1
                    [condition] => super
                    [price] => 11.33
                    [subtotal] => 11.33
                )

            [aXRlbTE=] => Array
                (
                    [add] => true
                    [name] => item1
                    [qty] => 1
                    [condition] => good
                    [price] => 23.99
                    [subtotal] => 23.99
                )
        )
)

我还应该注意,addToCart()结合saveDetails()方法与脚本大致相同,我只是将它们分成两部分。