thismethod
thismethod

Reputation: 533

How to store product quantities in an array

I have a data array that totals all the items in the cart for all the products as one number.

I've been trying to figure out a way to get a data array count() all the different totals of all the different items in the cart and have them presented in my data layer comma separated. I hope that makes sense.

if ($order->getId()) {
    $items = $order->getAllVisibleItems();
    $itemIds = array();
    $itemNames = array();
    $itemPrices = array();
    $itemMargins = array();
    $itemTypes = array();
    $itemGenders = array();
    $itemSports = array();
    $itemCategoryIds = array();
    $itemCategoryNames = array();
    /** @var Mage_Sales_Model_Quote_Item $item */
    foreach ($items as $item) {

        // Get the parent item - it is NOT included in the quote due to
        // customizations made by the OrganicInternet module for simple
        // product pricing. So I had to come up with another way to get it.
        $options = $item->getProductOptions();
        $parent = $item->getProduct();
        if (array_key_exists('info_buyRequest', $options)) {
            if (array_key_exists('cpid', $options['info_buyRequest'])) {
                $parentId = $options['info_buyRequest']['cpid'];
                $parent = Mage::getModel('catalog/product')->getCollection()
                    ->addAttributeToSelect('name')
                    ->addAttributeToSelect('season')
                    ->addAttributeToSelect('gender')
                    ->addAttributeToSelect('sport')
                    ->addAttributeToFilter('entity_id', $parentId)
                    ->getFirstItem();
            }
        }

        $itemIds[] = $item->getSku();
        $itemNames[] = $parent->getName();
        $itemPrices[] = $item->getBasePrice() ?: 0;
        $itemMargins[] = $this->_calculateMargin($parent, null, $item);
        $itemTypes[] = $parent->getAttributeText('season');
        $itemGenders[] = $parent->getAttributeText('gender');
        $itemSports[] = $parent->getAttributeText('sport') ?: 'Other';
        $categories = $this->_getAllCategoryIdsAndNames($item->getProduct());
        $itemCategoryIds[] = $categories['id'];
        $itemCategoryNames[] = $categories['name'];
    }

    // # Products

    $data['u1'] = count($items);

The above will return:

dataLayer = [{"visitorLoginState":"Logged out","visitorType":"NOT LOGGED IN","visitorLifetimeValue":0,"visitorExistingCustomer":"No","u1":2,"u2":["889623392590","889623135517"]

It shows a total of 2 products for the U1 variable and the two sku's for the u2 variable in the data array.

If i have multiple products for the first sku i want it to seperate the quantities. ie.. "u1":1,1,3

Would i use array_sumor some type of multi-dimensional array to acquire my needs?

Upvotes: 17

Views: 1561

Answers (5)

Leith
Leith

Reputation: 3299

Part of the issue with your data here is that everything in an $item is hidden behind an accessor. Rather than creating multitudes of arrays, I would suggest either creating a new object to house the information, or just modifying the $item directly.

Messing with the object directly has the risk of you accidentally using a variable name that exists in a protected or private scope though, so probably best to use your own, like so.

if ($order->getId()) {
    $items = $order->getAllVisibleItems();

    // only need one array, no need for all data points to have their own
    $myItems = [];

    /** @var Mage_Sales_Model_Quote_Item $item */
    foreach ($items as $item) {
        // basic shell
        $myItem = [];

        // get $options and $parent
        // ...

        // build your own data object
        $myItem['sku'] = $item->getSku();
        $myItem['name'] = $parent->getName();
        $myItem['price'] = $item->getBasePrice() ?: 0;
        $myItem['margin'] = $this->_calculateMargin($parent, null, $item);
        $myItem['type'] = $parent->getAttributeText('season');
        $myItem['gender'] = $parent->getAttributeText('gender');
        $myItem['sport'] = $parent->getAttributeText('sport') ?: 'Other';
        $categories = $this->_getAllCategoryIdsAndNames($item->getProduct());
        $myItem['categoryId'] = $categories['id'];
        $myItem['categoryName'] = $categories['name'];

        $myItems[] = $myItem;
    }

    // At this point, $myItems is manipulable by all the array_* functions

    // number of items e.g. 3
    $data['u1'] = count($myItems);
    // array of skus e.g. ["889623392590","889623392590","889623135517"]
    // note: can use objects for $myItem if on PHP 7 
    //       if you like -> notation better (in the loop)
    $skus = array_column($myItems, 'sku');
    // array of skus with counts e.g. ["889623392590" => 2, "889623135517" => 1]
    $skus_with_counts = array_count_values($skus);
    // just the counts (assuming indexes on other arrays must match) e.g. [2, 1]
    // note: might be useful if you want to keep the counts as an array in dataLayer
    $sku_counts = array_values($skus_with_counts);
    // if you want this as a comma-separated list for u1, e.g. "2,1"
    // note: will also work if you implode $skus_with_counts
    $data['u1'] = implode(',', $sku_counts);
    // get a list of unique SKUs (both will work), e.g. ["889623392590","889623135517"]
    $data['u2'] = array_unique($skus);
    $data['u2'] = array_keys($skus_with_counts);
}

Most of these kinds of PHP functions will work on your other data types as well if you want to do counting and clustering, and as you point out, you can run sum operations over them as well if you wish.

PHP array manipulation references: array_column, array_count_values, array_values, implode, array_unique, array_keys.

As a sidebar, Mage_Sales_Model_Quote_Item does have a getParentItemId() method available and a getQtyOptions method, which returns both the quantity and the product model.

Upvotes: 1

Bloafer
Bloafer

Reputation: 1326

Looking at the code it looks like it will only every return one product as the $parent variable is overwritten to get a first item. I have added a new variable named $itemProductCounts this will be returned to the output $data array as itemProductCounts I suspect this will always equal one.

<?php
if ($order->getId()) {
    $items              = $order->getAllVisibleItems();
    $itemIds            = array();
    $itemNames          = array();
    $itemPrices         = array();
    $itemMargins        = array();
    $itemTypes          = array();
    $itemGenders        = array();
    $itemSports         = array();
    $itemCategoryIds    = array();
    $itemCategoryNames  = array();
    $itemProductCounts  = array();
    /** @var Mage_Sales_Model_Quote_Item $item */
    foreach ($items as $item) {

        // Get the parent item - it is NOT included in the quote due to
        // customizations made by the OrganicInternet module for simple
        // product pricing. So I had to come up with another way to get it.
        $options    = $item->getProductOptions();
        $parent     = $item->getProduct();
        if (array_key_exists('info_buyRequest', $options)) {
            if (array_key_exists('cpid', $options['info_buyRequest'])) {
                $parentId = $options['info_buyRequest']['cpid'];
                $parent = Mage::getModel('catalog/product')->getCollection()
                    ->addAttributeToSelect('name')
                    ->addAttributeToSelect('season')
                    ->addAttributeToSelect('gender')
                    ->addAttributeToSelect('sport')
                    ->addAttributeToFilter('entity_id', $parentId)
                    ->getFirstItem();
            }
        }

        $itemIds[]                          = $item->getSku();
        $itemNames[]                        = $parent->getName();
        $itemPrices[]                       = $item->getBasePrice() ?: 0;
        $itemMargins[]                      = $this->_calculateMargin($parent, null, $item);
        $itemTypes[]                        = $parent->getAttributeText('season');
        $itemGenders[]                      = $parent->getAttributeText('gender');
        $itemSports[]                       = $parent->getAttributeText('sport') ?: 'Other';
        $categories                         = $this->_getAllCategoryIdsAndNames($item->getProduct());
        $itemCategoryIds[]                  = $categories['id'];
        $itemCategoryNames[]                = $categories['name'];
        $itemProductCounts[$item->getSku()] = count($parent);
    }

    // # Products

    $data['u1'] = count($items);
    $data['itemProductCounts'] = $itemProductCounts;

With that all being said, the code above should get you close to what you need, you should replace the line $itemProductCounts[$item->getSku()] = count($parent); with the correct array with the product counts for that SKU.

Upvotes: 1

mseifert
mseifert

Reputation: 5670

If i have multiple products for the first sku i want it to seperate the quantities. ie.. "u1":1,1,3

It is not exactly clear to me is the relationship between sku and product and which variables in your array refer to which. I make the following presumptions: 1) A product is equivalent to one $items element 2) A sku is a unique $itemIds[] value

I use the array key as a simple way to keep track for each unique sku and the value to keep track of the product count for the sku.

if ($order->getId()) {
    $items = $order->getAllVisibleItems();
    $itemIds = array();
    $itemNames = array();
    $itemPrices = array();
    $itemMargins = array();
    $itemTypes = array();
    $itemGenders = array();
    $itemSports = array();
    $itemCategoryIds = array();
    $itemCategoryNames = array();

    // My addition (UPDATE: fixed to the correct variable name)
    $uniqueItemIds = array();

    /** @var Mage_Sales_Model_Quote_Item $item */
    foreach ($items as $item) {

        // Get the parent item - it is NOT included in the quote due to
        // customizations made by the OrganicInternet module for simple
        // product pricing. So I had to come up with another way to get it.
        $options = $item->getProductOptions();
        $parent = $item->getProduct();
        if (array_key_exists('info_buyRequest', $options)) {
            if (array_key_exists('cpid', $options['info_buyRequest'])) {
                $parentId = $options['info_buyRequest']['cpid'];
                $parent = Mage::getModel('catalog/product')->getCollection()
                    ->addAttributeToSelect('name')
                    ->addAttributeToSelect('season')
                    ->addAttributeToSelect('gender')
                    ->addAttributeToSelect('sport')
                    ->addAttributeToFilter('entity_id', $parentId)
                    ->getFirstItem();
            }
        }
        // *******************************
        // My addition / changes
        $sku = $item->getSku();
        $itemIds[] = $sku;        // I don't use this but keep $itemIds for compatibility            

        // use the array key to track counts for each sku
        if (!isset($uniqueItemIds[$sku])){
            $uniqueItemIds[$sku] = 1;   // UPDATE: fixed to start at 1 not 0
        } else {
            $uniqueItemIds[$sku]++;
        }
        // *******************************
        $itemNames[] = $parent->getName();
        $itemPrices[] = $item->getBasePrice() ?: 0;
        $itemMargins[] = $this->_calculateMargin($parent, null, $item);
        $itemTypes[] = $parent->getAttributeText('season');
        $itemGenders[] = $parent->getAttributeText('gender');
        $itemSports[] = $parent->getAttributeText('sport') ?: 'Other';
        $categories = $this->_getAllCategoryIdsAndNames($item->getProduct());
        $itemCategoryIds[] = $categories['id'];
        $itemCategoryNames[] = $categories['name'];
    }

    // show # Products
    // "u1":1,1,3 NOTE: this should be a string => "u1":"1,1,3"
    $data['u1'] = "";
    foreach ($uniqueItemIds as $key => $val)
        // show unique skus in u2
        $data['u2'][] = $key;
        // show counts for each sku in u1
        if (strlen($data['u1'] == 0)){
            $data['u1'] = (string)$value;
        } else {
           $data['u1'] .= ("," . $value);
        }            
    }

Upvotes: 6

Mohd Abdul Mujib
Mohd Abdul Mujib

Reputation: 13928

How about something like...

if ($order->getId()) {
    .....
    .....
    .....
    /** @var Mage_Sales_Model_Quote_Item $item */
    $sku_based_array = array();

    foreach ($items as $item) {
        ......
        ......
        ......
        $categories = $this->_getAllCategoryIdsAndNames($item->getProduct());
        $itemCategoryIds[] = $categories['id'];
        $itemCategoryNames[] = $categories['name'];

        if (isset($sku_based_array[$item->getSku()])) {
            $sku_based_array[$item->getSku()] = $sku_based_array[$item->getSku()]++;
        } else {
            $sku_based_array[$item->getSku()] = 1;
        }
    }

    // # Products

    $data['u1'] = array_values($sku_based_array);

Upvotes: 1

GodlyHedgehog
GodlyHedgehog

Reputation: 86

I think you are mixing things.

In a simple sistem you should have:

  • Order has an array of OrderedItems

  • Each OrderedItem stores ProductObject and OrderedQuantity

  • And the ProductObject contains all product data.

So in your example instead of counting SKUs you must have $item->quantity field and you should work with that when you add/delete/edit order contents.

Upvotes: -1

Related Questions