I'm in the progress of making a shopping cart in PHP. To check if a user has selected multiple products, I put everything in an array ($contents). When I output it, I get something like "14,14,14,11,10". I'd like to have something like "3 x 14, 1 x 11, 1 x 10". What is the easiest way to do that? I really have no clue how to do it.
This is the most important part of my code.
$_SESSION["cart"] = $cart;
if ( $cart ) {
$items = explode(',', $cart);
$contents = array();
$i = 0;
foreach ( $items as $item ) {
$contents[$item] = (isset($contents[$item])) ? $contents[$item] + 1 : 1;
$i++;
}
$smarty->assign("amount",$i);
echo '<pre>';
print_r($contents);
echo '</pre>';
Thanks in advance.
Why not build a more robust cart implementation?
Consider starting with a data-structure like this:
$cart = array(
'lines'=>array(
array('product_id'=>14,'qty'=>2),
array('product_id'=>25,'qty'=>1)
)
);
Or similar.
Then you could create a set of functions that operate on the cart structure:
function addToCart($cart, $product_id, $qty){
foreach($cart['lines'] as $line){
if ($line['product_id'] === $product_id){
$line['qty'] += $qty;
return;
}
}
$cart['lines'][] = array('product_id'=>product_id, 'qty'=>$qty);
return;
}
Of course, you could (and perhaps should) go further and combine this data structure and functions into a set of classes. Shopping carts are a great place to start thining in an object-oriented way.
The built-in array_count_values function might does the job.
E.g:
<?php
$items = array(14,14,14,11,10);
var_dump(array_count_values($items));
?>
Outputs:
array(3) {
[14]=>
int(3)
[11]=>
int(1)
[10]=>
int(1)
}
You would benefit from using a multi dimensional array to store your data in a more robust structure.
For example:
$_SESSION['cart'] = array(
'lines'=>array(
array('product_id'=>14,'quantity'=>2, 'item_name'=>'Denim Jeans'),
...
)
);
Then to add new items to the cart you can simply do this:
$_SESSION['cart'][] = array('product_id'=45,'quantity'=>1, 'item_name'=>'Jumper');
When you let a user add an item you need to add it in the right position in the array. If the product id already exist in the array, you need to update it. Also always be careful of users trying to enter zero or minus numbers!
Related
I made a simple import script and I'm trying to programatically save 3 custom attributes (att1, att2, att3) together with all other info (name, description, price, category..).
So basically I have:
public function insert_product($data) {
$product = Mage::getModel('catalog/product');
try {
$sku = $data['code'];
if ($this->prodottiImportati[$sku]) {
$sku = $data['code'] . '-1';
}
$this->prodottiImportati[$sku] = true;
$product->setSku($sku);
$product->setName($data['name']);
$product->setDescription($data['desc']);
$product->setShortDescription($data['short_desc']);
$product->setManufacturer('');
$product->setPrice($data['price']);
$product->setTypeId('simple');
$product->setAttributeSetId($this->attributeSet);
$categorie = $this->get_categories($data);
$product->setCategoryIds($categorie);
$product->setWeight($data['peso']);
$product->setTaxClassId(2); // taxable goods
$product->setVisibility(4); // catalog, search
$product->setStatus(1); // enabled
$product->setWebsiteIds($data['store_id']);
$stockData = $product->getStockData();
$stockData['qty'] = $data['qty'];
if ($data['quantita'] > 0) {
$stockData['is_in_stock'] = 1;
} else {
$stockData['is_in_stock'] = 0;
}
$stockData['manage_stock'] = 1;
$stockData['use_config_manage_stock'] = 0;
$product->setStockData($stockData);
$product->setIsMassupdate(true)->setExcludeUrlRewrite(true);
$product->save();
$productID = $product->getId();
} catch(Exception $e) {
echo ($e->getMessage());
}
return $productID;
}
First thing I tryed was adding a
$productID = $this->insert_product($data);
Mage::getSingleton('catalog/product_action')->updateAttributes(
array($productID), array(
'att1' => $data['att1'],
), $data['store_id']);
So basically updating things after the insert function was called, using the ID got after the insert. store_id is the ID of the store in that given language. Didn't save anything.
Second attempt, I follwed this: Magento add custom options with programmatically importing products
I tryed that within the insert_product function and also outside after $productID = $this->insert_product($data); Neither worked.
Last I tryed a magical $product->setAtt1('value'); witin the insert_product function, not sure how Magento would understand how to set att1 that way, but...you know, I read it somewhere and I gave it a try ;)
att1, att2 and att3 are spelled lowercase, althoug they have an uppercase label (think that dosen't matter here), they are part of an attribute group (I'm passing it with $product->setAttributeSetId($this->setAttributi)) and they are all multiple selection attributes, so I could in teory pass multiple values to them.
I'm sure I'm missing something on the way. Can anyone help?
After 10 more minutes since I wrote here, I was able to find the way. I took me forever to solve it.
The clue of this is that you have to add attributes ID, not values. That happens at least for me with multiple selection attributes, not sure if it's true all the time.
Here is how I did:
In the function insert_product I added:
$optionId = $this->get_option_id_by_code('att1', 'Value of the attribute you need to add');
$product->setAtt1($optionId);
So if yor attribute is named, let's say "brand" it will be:
$optionId = $this->get_option_id_by_code('brand', 'Nike');
$product->setBrand($optionId);
If your attribute can have multiple values, you need to change the code above to:
$optionId = array();
foreach ($myAttributesArray as $someValues) {
$optionId[] = $this->get_option_id_by_code('att1', $someValues);
}
$product->setAtt1($optionId);
The foreach is just an example, you need to loop through your mutiple values and get the respective ID and add them all toghether with setAtt1 passing them as an array. I'm working on an improved version where the get_option_id_by_code function does all at once in a more efficient way. This is kust a "basic" version that works, feel free to make it fancy and smart.
Then I created an other function called get_option_id_by_code like this:
protected function get_option_id_by_code($attrCode, $optionLabel) {
$attrModel = Mage::getModel('eav/entity_attribute');
$attrID = $attrModel->getIdByCode('catalog_product', $attrCode);
$attribute = $attrModel->load($attrID);
$options = Mage::getModel('eav/entity_attribute_source_table')
->setAttribute($attribute)
->getAllOptions(false);
foreach ($options as $option) {
if ($option['label'] == $optionLabel) {
return $option['value'];
}
}
return false;
}
To be honest I found this with a collage of other sources / authors, so I need to be thankful to a bunch of smarter programmers here and there, since it took a while for me to strouggle with this simple task I wrote the solution here hoping to help you guys. Thanks!
I am not getting the concept of two dimensional arrays in PHP. I am trying to implement a cart system in which an array Session variable store productid and the quantity of it.
For every new entry if it exists its quantity should be increased or if it does'nt then a new id should be added.
Here is my initial code.
function cart_increment_ajax($data, $qtt) {
$_SESSION['count']+=$qtt;
set_cart( $data );
echo $_SESSION['count'];
}
function initialise_cart( ) {
$_SESSION['cart'] =array( );
$_SESSION['totalprice'] = 0;
}
function set_cart( $pid ) {
if(!isset($_SESSION['cart'])) {
initialise_cart( );
}
//else if( int $_SESSION['cart'] pid exists increment count ))
else
// ($_SESSION['cart'] add new pid.
}
I am not getting how to implement the commented lines through Multidimensional associative array ?
A small quick n dirty example of a multi-array in a session keeping a cart
<?php
function add_to_cart($product_id,$count)
{
// no need for global $_SESSION is superglobal
// init session variable cart
if (!isset($_SESSION['cart']))
$_SESSION['cart'] = array();
// check if product exists
if (!isset($_SESSION['cart'][$product_id]))
$_SESSION['cart'][$product_id]=$count;
else
$_SESSION['cart'][$product_id]+=$count;
}
// add some foos and a bar
add_to_cart('foo',2);
add_to_cart('foo',1);
add_to_cart('bar',1);
print_r($_SESSION['cart']);
?>
This will produce
Array
(
[foo] => 3
[bar] => 1
)
HTH
Use the product ID as an index in your array, then simply increment it by using ++.
$_SESSION['cart'][$pid]++;
So I have my query, its returning results as expect all is swell, except today my designer through in a wrench. Which seems to be throwing me off my game a bit, maybe its cause Im to tired who knows, anyway..
I am to create a 3 tier array
primary category, sub category (which can have multiples per primary), and the item list per sub category which could be 1 to 100 items.
I've tried foreach, while, for loops. All typically starting with $final = array(); then the loop below that.
trying to build arrays like:
$final[$row['primary]][$row['sub']][] = $row['item]
$final[$row['primary]][$row['sub']] = $row['item]
I've tried defining them each as there own array to use array_push() on. And various other tactics and I am failing horribly. I need a fresh minded person to help me out here. From what type of loop would best suit my need to how I can construct my array(s) to build out according to plan.
The Desired outcome would be
array(
primary = array
(
sub = array
(
itemA,
itemB,
itemC
),
sub = array
(
itemA,
itemB,
itemC
),
),
primary = array
(
sub = array
(
itemA,
itemB,
itemC
),
sub = array
(
itemA,
itemB,
itemC
),
),
)
Something like this during treatment of your request :
if (!array_key_exists($row['primary'], $final)) {
$final[$row['primary']] = array();
}
if (!array_key_exists($row['sub'], $final[$row['primary']])) {
$final[$row['primary']][$row['sub']] = array();
}
$final[$row['primary']][$row['sub']][] = $row['item'];
Something like this....
$final =
array(
'Primary1'=>array(
'Sub1'=>array("Item1", "Item2"),
'Sub2'=>array("Item3", "Item4")
),
'Primary2'=>array(
'Sub3'=>array("Item5", "Item6"),
'Sub4'=>array("Item7", "Item8")
),
);
You can do it using array_push but it's not that easy since you really want an associative array and array_push doesn't work well with keys. You could certainly use it to add items to your sub-elements
array_push($final['Primary1']['Sub1'], "Some New Item");
If I understand you correctly, you want to fetch a couple of db relations into an PHP Array.
This is some example code how you can resolve that:
<?php
$output = array();
$i = 0;
// DB Query
while($categories) { // $categories is an db result
$output[$i] = $categories;
$ii = 0;
// DB Query
while($subcategories) { // $subcategories is an db result
$output[$i]['subcategories'][$ii] = $subcategories;
$iii = 0;
// DB Query
while($items) { // $items is an db result
$output[$i]['subcategories'][$ii]['items'][$iii] = $items;
$iii++;
}
$ii++;
}
$i++;
}
print_r($output);
?>
let's say i have $_SESSION['cart']; when I print this
echo "<pre>",print_r($_SESSION['cart']),"</pre>";
it will show something like
Array
(
[1] => 2
[2] => 2
)
where the keys are the product IDs and the value is the quantity of each product.
so, if I would want to delete product no. 2 from that session array,
how am to do that ?
I tried the fastest function that came to my mind
public function removeItem($id2){
foreach($_SESSION['cart'] as $id => $qty) {
if ($id == $id2){
unset($_SESSION['cart'][$id]);
}
}
}
it deleted the whole $_SESSION['cart'] data :(
unset($_SESSION['cart'][$id2]);
You don't need to walk through whole array in foreach for this. Simple is better than complicated :)
Why are you looping through? If you get the id you want do delete as a parameter anyway, you can do this:
public function removeItem($id2) {
unset($_SESSION['cart'][$id2]);
}
If you want to clear the id just do :
$_SESSION['cart'][$id] = null;
Hope this help
just do
public function removeItem($id){
unset($_SESSION['cart'][$id]);
}
i am writing a magento product exporter, that writes a couple of attributes into a csv file. one attribute is called the "category string" and its method looks like:
...
foreach($products as $_product) {
...
$productId = $_product->getSku();
$productCategory = getCategoryString($_product['category_ids']);
...
}
...
function getCategoryString($numbers) {
$catString = '';
$catModel = Mage::getModel('catalog/category')->setStoreId(Mage_Core_Model_App::ADMIN_STORE_ID);
$ex = explode(',', $numbers);
foreach ($ex as $i => $e) {
if ($i > 0) {
$catString .= $catModel->load($e)->getName();
if ($i < (count($ex)-1))
$catString .= ' > ';
}
}
$ex = NULL;
$numbers = NULL;
$catModel->unsetData();
unset($catModel);
$catModel = NULL;
return $catString;
}
but after each iteration the method call costs about 1MB for each product and i have about 9000 products! i cannot clean up the $catModel variable! the $catModel = NULL and unset($catModel) lines have no effects. what am i doing wrong? how can i force to unset the object?!
We had the same problem with a cron for Magento, I know that it isn't the best way to do it but we needed to do it quickly.
Our solution was creating a new PHP file with the necessary code to do one single operation. From magento we get a product list and then call with exec() to this external PHP file product by product.
Something like this:
foreach($products as $_product) {
...
exec("do_the_work.php {$_product->getSku()}");
...
}
Hope it helps.
so your script would be so much cooler if you
get all catalog ids from all the products you have as an array
load the category collection with IN() clause with the category names you need
foreach your product collection one more time and select the neccecary category id's from preloaded collection with just the right elements
profit $$$$ cause you are not using memory like its unlimited for you
much much cooler thing would be joining the category names directly to product collection, that would consume even less resources