How to compare values in a single foreach loop php - php

I am working on opencart.I dont want to allow users to add same product multiple times in cart. for this i have a logic that i want to compare the products in cart. I will get the the product id of each product(how many the user added by clicking add to cart) than i will compare those ids. If they are same i will show them error message else they can carry on. For this logic i have used this code till now.
$products = $this->cart->getProducts();
foreach ($products as $product)
{
$p_id=$product['product_id'];
}
But i dont get that how will i compare 2 product ids in foreach loop. and than add my logic that if product ids are equal show error message.

You can simply check it at the time when user add a product to cart. To do so modify add function in controller->checkout->cart.php
In public function add() {
Add
$products = $this->cart->getProducts();
if($products){
foreach ($products as $product)
{
if($this->request->post['product_id'] == $product['product_id']){
$json['error']['blabla'] = 'Your warning message.';
break;
}
}
}
Before
if (!$json) {
And display that error wherever you want to display. That's it.

you can get the value of new product id and than compare it like this
//get product id to be added
$new_product = "get ID";
$products = $this->cart->getProducts();
foreach ($products as $product)
{
$p_id=$product['product_id'];
//compare with new product_id with existing
if ($_pid == $new_product){
echo " Product already exists!!";
}
}

$products = $this->cart->getProducts();
$exist = false;
foreach ($products as $product)
{
if ($p_id == $product['product_id']) {
$exist = true;
break;
}
}
if (!$exist) {
//add product co cart
}

Try this way
$products = $this->cart->getProducts();
$p_id = '';
foreach ($products as $product)
{
if($p_id != $product['product_id']) {
$p_id=$product['product_id'];
}else{
echo " Product already exists!!";
}
}

This will get you both a unique list of ID's and a list of ID's that needed to be removed to make the list unique.
// get the list of ID's
$products = $this->cart->getProducts();
$all = array();
foreach ($products as $product)
{
$all[] = $product['product_id'];
}
// Flip the array twice to just get the unique ID's
$unique = array_flip(array_flip($all));
// Get a list of ID's that were lost
$difference = array_diff_assoc($all, $unique);

Related

Adding multiple values to same key in array php

I want to add multiple values into arrays, for same key.
I have this code:
public function getOnlySellers()
{
$sellers[] = array();
foreach ($this->getProducts() as $product) {
$product_id = $product['product_id'];
$getseller = $this->getSellerbyProduct($product_id);
$sellers[$getseller] = $product_id;
}
return $sellers;
}
Here I have for example: seller 1 with values: 100 and 101
Seller 2 with values: 107
But on my code, on seller 1 for example, is showing only last value 101, but not both.
What is wrong ?
And the call code:
$call = $this->cart->getOnlySellers();
foreach ($call as $seller => $products)
{
$show = "$show <br> $seller has value $products";
}
Thanks!
You could add an array of product ids to your $sellers array, allowing you to assign multiple product_ids to each seller. This [] operator will push the $product_id onto a new array at $sellers[$getseller].
$sellers[$getseller][] = $product_id;
The full code then being:
public function getOnlySellers()
{
$sellers[] = array();
foreach ($this->getProducts() as $product) {
$product_id = $product['product_id'];
$getseller = $this->getSellerbyProduct($product_id);
$sellers[$getseller][] = $product_id;
}
return $sellers;
}
When you output the values, you could use implode to glue the product ids together:
$call = $this->cart->getOnlySellers();
foreach ($call as $seller => $products)
{
$show = "$show <br> $seller has value ".implode(', ', $products);
}

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?
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);
}
}
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);
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.
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.
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.

Augment category detail with product information

I currently have a piece of code that puts together data about all of the categories in Magento. I would like to add product details, including but not limited to:
price
sku
image url
I'm having trouble adding those attributes to the response
<?php
require_once('../app/Mage.php'); //Path to Magento
umask(0);
Mage::app();
function getCategoryTree($recursionLevel, $storeId = 1)
{
$parent = Mage::app()->getStore()->getRootCategoryId();
$tree = Mage::getResourceModel('catalog/category_tree');
$nodes = $tree->loadNode($parent)
->loadChildren($recursionLevel)
->getChildren();
$tree->addCollectionData(null, false, $parent);
$categoryTreeData = array();
foreach ($nodes as $node) {
$categoryTreeData[$node->getData('entity_id')] = getNodeChildrenData($node);
}
return $categoryTreeData;
}
function getNodeChildrenData(Varien_Data_Tree_Node $node)
{
$data = array(
'title' => $node->getName(),
'url' => $node->getData('url_key'),
'price' => $node->getPrice(),
);
foreach ($node->getChildren() as $childNode) {
if (!array_key_exists('children', $data)) {
$data['children'] = array();
}
$data['children'][$childNode->getData('entity_id')] = getNodeChildrenData($childNode);
}
return $data;
}
print_r(json_encode(getCategoryTree(100)));
?>
You can easily bring in information about products, but you'll need to load product collections along the way. So far you're dealing with only category models (as mentioned in the comments) which don't contain any product data.
To load the set of products associated with a category, use:
<?php
...
$products = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect({attribute})
->addCategoryFilter($category)
->load();
$category should be a category object and $products is a collection of products that you can loop through. For each product attribute that you are interested in, add an addAttributeToSelect() entry with the name of the attribute in the pares. You can then get product details by writing things like:
<?php
...
foreach($products as $product) {
$price = $product->getPrice();
}

magento programatically update sort_order on option dropdown labels

There is info on the web about how to update attribute option labels
(e.g. http://www.webspeaks.in/2012/05/addupdate-attribute-option-values.html) but how do I only update the sort order?
The reason I wanted to do this was that I wanted to sort manufacturer by product view count. So the manufacturers with the most global views are sorted to the top.
Its really laborious. You have to create an array of labels for each store so that you don't overwrite anything when you update. You then can attach the sort orders to that array. Here is the code to make that work:
//build array of labels
$attribute_model = Mage::getModel('eav/entity_attribute');
$attribute_code = $attribute_model->getIdByCode('catalog_product', 'manufacturer');
//get default label values for option
$optionCollection = Mage::getResourceModel('eav/entity_attribute_option_collection')
->setAttributeFilter($attribute_code)
->setPositionOrder('desc', true)
//->setStoreFilter($_eachStoreId)
->load();
//build the data required to reset the labels to what they were (what a pain)
foreach ($optionCollection as $option)
$data['value'][$option->getData('option_id')][0] = $option->getData('value');
//go through the stores one by one
foreach (Mage::app()->getStores() as $_eachStoreId => $val)
{
//get the labels for this attribute for that store
$optionCollection = Mage::getResourceModel('eav/entity_attribute_option_collection')
->setAttributeFilter($attribute_code)
->setPositionOrder('desc', true)
->setStoreFilter($_eachStoreId)
->load();
//build the data required to reset the labels to what they were (what a pain)
foreach ($optionCollection as $option)
if( $data['value'][$option->getData('option_id')][0] != $option->getData('value') )
$data['value'][$option->getData('option_id')][$_eachStoreId] = $option->getData('value');
else
$data['value'][$option->getData('option_id')][$_eachStoreId] = '';
}
//echo "<pre>"; print_r($data); die;
//just load all products with view counts and build manufacturerValueId => totalViews array
$products = Mage::getResourceModel('reports/product_collection')
->addViewsCount()
->addAttributeToSelect('manufacturer')
;
foreach($products as $product){
if ($product->getManufacturer()!='') $data['order'][$product->getManufacturer()] += $product->getViews();
}
//now we've gotta invert this array
//put largest value at top
arsort($data['order']);
foreach($data['order'] as $key => $value)
{
if(!isset($highest)) $highest = $value;
$newData['order'][$key] = $highest - $value;
}
$data['order'] = $newData['order']; unset($newData);
//echo "<pre>"; print_r($data); die;
$data = array('option' => $data );
//Get the eav attribute model
$attr_model = Mage::getModel('catalog/resource_eav_attribute');
//Load the particular attribute by id
$attr_model->load($attribute_code);
//Add data to our attribute model
$attr_model->addData($data);
//echo "<pre>"; print_r($attr_model->getData()); die;
//Save the updated model
try {
$attr_model->save();
/**
* Clear translation cache because attribute labels are stored in translation
*/
$session = Mage::getSingleton('adminhtml/session');
Mage::app()->cleanCache(array(Mage_Core_Model_Translate::CACHE_TAG));
$session->setAttributeData(false);
return;
} catch (Exception $e) {
echo "<pre>"; print_r($e->getMessage());
echo "<pre>"; print_r($data);
return;
}
so i realize this is a super necro but if you have the attribute option_id available the easiest thing to do here is
$resource = Mage::getSingleton('core/resource');
$writeCxn = $resource->getConnection('core_write');
$query = "update 'eav_attribute_option' SET sort_order='".$sort_order."' WHERE 'option_id'='".$option_id."';";
$writeCxn->query($query);
Throw that in a foreach loop over your resorted array and no mucking with trying to rewrite labels and what not. The gap here is if you are trying to apply sort orders on a store scope. This will not work for that but, if you just need one sort order for the options list. This is the way to go.

Check if specific product has been bought on success page

On the success page after checkout (success.phtml), I'd like to run a script only if a certain product ID has been bought. Is this possible?
I'm using Magento 1.4.2.
Try adding this to Success.phtml
$order = Mage::getModel('sales/order')->loadByIncrementId($this->getOrderId());
$items = $order->getItemsCollection();
$sku = $ids = array();
foreach($items as $item){
//$sku[] = $item->getSku();
$p_ids[] = $item->getProductId();
}
$p_id = 16;
if(in_array($p_id, $p_ids)){
//run script
}
This sort of logic might work on success.phtml page.
$
if($this->getOrderId()) {
$found = false;
$skuToFind = 'abc';
$order = Mage::getModel('sales/order')->loadByIncrementId($this->getOrderId());
$items = $order->getAllItems();
foreach ($items as $i => $item) {
if($item->getSku() == $skuToFind) {
$found = true; break;
}
}
if($found) { echo "Product Found"; } else { echo "No Found"; }
?>
Well, you only need to find the cart variables. I'm not sure the exact variables but echoing out the $_SESSION will show you where they are. Check out the following example code:
if(in_array('2324242', $_SESSION['product_ids'])
{//in this case 2324242 is the product ID you are looking for
//Require_once ('script');
//Or redirect to script.php
}

Categories