Array push shopping cart in PHP - php

I've just started a PHP course. I was asked to create a shopping cart function using array_push. I don't fully understand the code, can anyone help?
I've created an array called $cart
$cart = [
'user' => 'sholmes',
'items' => [$camera, $lens]
We were then asked to create a function called create item, to put items into the shopping cart. The answer is below:
function create_item(&$cart, $item) {
array_push($cart['items'], $item);
return count($cart) - 1;
}
What I don't understand is the last line of code. Why is the return count $cart -1? I thought the point of array_push was to add items to the cart? Our teacher talked through the solution but I don't quite understand it. Any help welcome!
Thanks
Vicki

The function create_item(&$cart, $item) in your case along with adding a new item to the $cart returns the position of the last added item.But array_push function already returns the new number of elements in the array.The function could be simplified to the following:
function create_item(&$cart, $item) {
return array_push($cart['items'], $item) - 1;
}
http://php.net/manual/en/function.array-push.php

Related

How can I "temporary" store some values from a decoded JSON table?

I am constructing a function that is making a call with API to db and returns me JSON data. The json contains orders and I have already decoded them in php array. Every order has properties such as "product_id" and "quantity". I want to temporarily store the "quantity" property somewhere because I need to sum all the products with the same product_id. Any suggestion how to do this?
I'm in a bit of a hurry, but wanted to see if I could help you out.
$quantities = [];
//Loop through all the orders
foreach ($orders as $order) {
//Loop through the orderrows
foreach ($order->getOrderRows() as $orderRow) {
if (array_key_exists($orderRow->getProductName(), $quantities)) {
//The product is already in the quantities array, so the quantity of this orderrow is added to the total
$quantities[$orderRow->getProductName()] =
($quantities[$orderRow->getProductName()] + (int) $orderRow->getItemQuantity());
} else {
//If this is the first time the product is encountered add the product and its quantity to the quantities array
$quantities[$orderRow->getProductName()] = (int) $orderRow->getItemQuantity();
}
}
}
This is going to have the following result, showing you the product names along with their quantities:
$quantities = [
'foo' => 12,
'bar' => 3,
];
You may use the session variable to store these values.

Add property of each element in array to a new array

I'm using CakePHP to create a products database system. In CakePHP, I have an array of all products in the 'products' table. Each product (an element in the 'products' array) has a function 'toArray()'. This converts the product into an associative array. How could I take an array of all the products and add the 'toArray()' of each product to a new array. This is my current flow:
$products = [$product1, $product2, $product3];
$newArr = [];
foreach($products as $product) {
$newArr[] = $product->toArray();
}
Is there a one-liner for something like this?
I don't think you could quite oneline this (without functionalizing it, anyway), but you don't need to duplicate data unless you need to keep the original format as well as the reformatted version.
foreach($products as $key => $product){
$products[$key] = $product->toArray();
}
Will change your exisiting array to the reformatted version.

how to remove a particular key => value from a session array?

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]);
}

Magento: paginate filtered product collection

i want to filter and paginate a product collection. everything is fine - except pagination. im just getting the whole collection back, instead of 3 items for the first page.
//fetch all visible products
$product_collection = Mage::getModel('catalog/product')->getCollection();
//set wanted fields (nescessary for filter)
$product_collection->addAttributeToSelect('name');
$product_collection->addAttributeToSelect('description');
$product_collection->addAttributeToSelect('price');
$product_collection->addAttributeToFilter('visibility', array('neq' => 1));
//filter by name or description
$product_collection->addFieldToFilter(array(
array('attribute'=>'name','like'=>$sTerm),
array('attribute'=>'description','like'=>$sTerm)
));
//filter for max price
foreach ($product_collection as $key => $item) {
if($item->getPrice() >= $priceTo){
$product_collection->removeItemByKey($key);
}
}
//pagination (THIS DOESNT WORK!)
$product_collection->setPageSize(3)->setCurPage(1);
//TEST OUTPUT
foreach ($product_collection as $product) {
echo $product->getName().'<br />';
}
thanks for your support!
You are so close! Try moving that $product_collection->setPageSize(3)->setCurPage(1); line before the first foreach() iteration over the collection.
Magento collections are lazy-loaded. Until you directly load() them (or implicitly load them via a call to count() or foreach()) you can modify the collection properties which affect the underlying query (EDIT: see note below). Once the collection has been loaded explicitly or implicitly though you will only get the members of the _items property that have been set.
FYI you can call clear() to leave the original query-affecting properties (filters, sorters, limits, joins, etc) in place and then add further properties.
HTH
EDIT: Actually, adjusting query properties is always possible regardless of _items load state, but the effect won't be visible until the collection is regenerated.
Thanks #Ben! You gave me the right hint. Now it does work! Basically I'm creating another collection and filter this one by the ids of the already filtered items. Afterwards its easy to add pagination to that new collection. That's the working code:
//fetch all visible products
$product_collection = Mage::getModel('catalog/product')->getCollection();
//set wanted fields (nescessary for filter)
$product_collection->addAttributeToSelect('name');
$product_collection->addAttributeToSelect('description');
$product_collection->addAttributeToSelect('price');
$product_collection->addAttributeToFilter('visibility', array('neq' => 1));
//filter by name or description
$product_collection->addFieldToFilter(array(
array('attribute'=>'name','like'=>$sTerm),
array('attribute'=>'description','like'=>$sTerm)
));
//filter for max price
foreach ($product_collection as $key => $item) {
if($item->getPrice() >= $priceTo){
$product_collection->removeItemByKey($key);
}
}
//build id array out of filtered items (NEW!)
foreach($product_collection as $item){
$arrProductIds[]=$item->getId();
}
//recreate collection out of product ids (NEW)
$product_filtered_collection = Mage::getModel('catalog/product')->getCollection();
$product_filtered_collection->addAttributeToFilter('entity_id', array('in'=>$arrProductIds));
//add pagination (on new collection) (NEW)
$product_filtered_collection->setPageSize(3)->setCurPage(1);
//TEST OUTPUT
foreach ($product_filtered_collection as $product) {
echo $product->getName().'<br />';
}

Invoicing a partial order; totals aren't updated

In our order proces it is possible to send an invoice for a partial order. So when a couple of order lines are being shipped, an invoice have to be send also.
To make this possible I use this code:
$invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice($items);
if (!$invoice->getTotalQty()) {
Mage::throwException(Mage::helper('core')->__('Cannot create an invoice without products.'));
}
$invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE);
$invoice->register();
$transactionSave = Mage::getModel('core/resource_transaction')
->addObject($invoice)
->addObject($invoice->getOrder());
$transactionSave->save();
$invoice->sendEmail();
$invoice->setEmailSent(true);
$invoice->save();
Where the $items variable is an array containing the order ids and the amount of products to be invoiced.
The created invoice shows the correct products to be invoiced, but somehow the totals aren't updated. The totals still are the totals of the complete order, instead of the partial invoice.
I probably have to update or recalculate the totals but can't find the right code to force the update.
Anyone around who can put me in the right direction?
Well, it seems I have found the problem. The functionality as described above works manually executing it in the administrator interface. The code as enclosed above I only got to work by changing a core file of Magento.
If you change line 103 of Mage_Sales_Model_Service_Order from continue; to $qty = 0; the functionality works.
In short, this is what happens. With continue the second row item isn't added to the invoice which the invoice makes thinks the curren item is the last item of the whole order and therefore needs to invoice the complete outstanding amount. In my case the invoice I did want to invoice and the row I didn't want to invoice.
I've submitted it as issue on the Magento issue list.
Today I faced with exactly this problem, but I found a more elegant way to solve it without editing the core. The solution is to pass the products that we don't want to invoice, with 0 quantity.
In this way, the code you changed in core will act exactly like in your solution :)
As an example if I have 2 products in my order:
array(
1234 => 1,
1235 => 2
)
passing this array:
$qtys = array(
1234 => 1,
1235 => 0
)
will force this code:
// Mage_Sales_Model_Service_Order: lines 97-103
if (isset($qtys[$orderItem->getId()])) { // here's the magic
$qty = (float) $qtys[$orderItem->getId()];
} elseif (!count($qtys)) {
$qty = $orderItem->getQtyToInvoice();
} else {
continue; // the line to edit according to previous solution
}
to act exactly like in your solution, so you don't have to edit core code.
Hope it helps :)
OK - took me a bit, but now I see how to correctly create the array.
foreach ($items as $itemId => $item) {
$itemQtyToShip = $item->getQtyToShip()*1;
if ($itemQtyToShip>0) {
$itemQtyOnHand = $stockItem->getQty()*1;
if ($itemQtyOnHand>0) {
//use the order item id as key
//set the amount to invoice for as the value
$toShip[$item->getId()] = $itemQtyToShip;
} else {
//if not shipping the item set the qty to 0
$toShip[$item->getId()] = 0;
}
}
$invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice($toShip);
This creates a proper invoice.

Categories