I have managed to implement OOP of Cart Basket
An Item contain 1 or more options.
If I add same OptionID again then the number of quantity should increase rather than creating another Option Object. How can that be done?
If I add same ItemID again, it should refuse to create another Item object.
Also is my OOP is good?
class Cart {
public $item = array();
public function addItem($id) {
$item = new Item();
$item->setItem($id);
$this->item[] = $item;
return $item;
}
}
class Item {
private $id = array();
private $option = array();
public function setItem($id) {
$this->id = $id;
return $this;
}
public function addOption($id) {
$option = new Option();
$option->setOption($id);
$this->option[] = $option;
}
}
class Option {
private $quantity;
private $id;
public function setOption($id) {
$this->quantity = 1;
$this->id = $id;
return $this;
}
}
$cart = new Cart();
//ItemID 10
$item = $cart->addItem(10);
//OptionID
$item->addOption(11);
$item->addOption(22);
$item->addOption(22); //should increase quantity
//It should not create another object because we already have Item Object of ItemID10
$item = $cart->addItem(10);
$Shop = $cart;
echo "<pre>";
print_r($Shop);
echo "</pre>";
If you can have only one item with the unique id in the cart - then rewrite the addItem() method like this:
public function addItem($id) {
$result = false;
if (empty($this->item[$id])) {
$item = new Item();
$item->setItem($id);
$this->item[$id] = $item;
$result = $item;
}
return $result;
}
The same is with addOption() method:
public function addOption($id) {
if (empty($this->option[$id])) {
$option = new Option();
$option->setOption($id);
$this->option[$id] = $option;
}
else {
$this->option[$id]->setQuantity($this->option[$id]->getQuantity() + 1);
}
}
And of course you should implement setQuantity() and getQuantity() methods in Option class.
Hope this helps.
Partialy rewrote the code and tested:
<?php
class Cart {
public $items = array();
public function addItem($id) {
if(array_key_exists($id, $this->items)){
$item = $this->items[$id];
}else{
$item = new Item($id);
$this->items[$id] = &$item;
}
return $item;
}
}
class Item {
private $id;
private $options = array();
public function __construct($id) {
$this->id = $id;
return $this;
}
public function addOption($id) {
if(array_key_exists($id, $this->options)){
$this->options[$id]->addQuantity();
}else{
$option = new Option($id);
$this->options[$id] = $option;
}
}
}
class Option {
private $quantity;
private $id;
public function __construct($id) {
$this->quantity = 1;
$this->id = $id;
return $this;
}
public function addQuantity()
{
$this->quantity++;
}
}
$cart = new Cart();
//ItemID 10
$item = $cart->addItem(10);
//OptionID
$item->addOption(11);
$item->addOption(22);
$item->addOption(22); //should increase quantity
//It should not create another object because we already have Item Object of ItemID10
$item = $cart->addItem(10);
$Shop = $cart;
echo "<pre>";
print_r($Shop);
echo "</pre>";
?>
Related
I am trying to implement the getCost() function using a forloop but i am new to php and having trouble with understanding how to implement. i just keep getting error saying undefined variable.
Here is my code
<?php
class Burger {
public $title = '';
private $ingredients = array();
public function __construct($n) {
$this->name = $n;
}
public function addIngredient($ing) {
array_push($this->ingredients, $ing);
}
public function getCost() {
foreach( $ingredients as $ingredient=> $costDollars){
$price += $costDollars;
return $price;
}
} }
class Ingredient {
public $name = 'Ingredient'; public $costDollars = 0.0;
public function __construct($n, $c) {
$this->name = $n;
$this->costDollars = $c;
} }
$myBurger = new Burger('Tasty Burger');
$myBurger->addIngredient(new Ingredient('Meat', 0.3));
$myBurger->addIngredient(new Ingredient('Cheese', 0.2));
$myBurger->addIngredient(new Ingredient('Beetroot', 0.2));
$myBurger->addIngredient(new Ingredient('Pineapple', 0.4));
echo $myBurger->getCost(); ?>
You're forgetting $this when you're trying to access the class property $ingredients:
public function getCost() {
$price = 0;
foreach( $this->ingredients as $ingredient){
$price += $ingredient->costDollars;
}
return $price;
}
As you can see in the above code, the return-statement is also moved after the loop. If you have the return in your loop, the variable will be returned after the first iteration.
<?php
class Burger {
public $title = '';
private $ingredients = array();
public function __construct($n) {
$this->name = $n;
}
public function addIngredient($ing, $cost) {
$this->ingredients += array($ing => $cost); // Wont overide! EXTRA CHEEZ PLZ
}
public function getCost() {
//forloop
$totalprice = 0; // Start Register Cha Ching!
foreach($this->ingredients as $ing => $price){ // Add Items (*scanner Beeps*
$totalprice += $price;
} // All Done with items, let return cost
return $totalprice; // Return Value to Function Call
}
}
$myBurger = new Burger('Tasty Burger');
$myBurger->addIngredient('Meat', 0.3);
$myBurger->addIngredient('Cheese', 0.2);
$myBurger->addIngredient('Beetroot', 0.2);
$myBurger->addIngredient('Pineapple', 0.4);
echo $myBurger->getCost(); ?> // ECHO Value to Function Call
The problem am having is keeping my inventory variable keep up with the changes made by different objects. For example, the $me object buys 4 items, which deducts from the inventory and leaves 6 in the inventory that is good. Then I make a new object $l, but the inventory starts from 10 again, instead of the new current inventory of 6.
Below is my PHP code for my class
class cashRegister {
public $total = 0;
public $name;
public $discount;
public $lastamount;
public $inventory = 10;
public function __construct($name, $discount) {
$this->name = $name;
$this->discount = $discount;
}
public function add($itemCost) {
$this->total += $itemCost;
$this->lastamount = $itemCost;
}
public function scan($item, $quantity) {
switch ($item) {
case "eggs" :
$this->add ( 1 * $quantity);
$this->inventory($quantity);
break;
case "news" :
$this->add(2 * $quantity);
$this->inventory($quantity);
}
//$this->inventory -= $quantity;
}
public function inventory($quantity) {
$this->inventory -= $quantity;
}
public function staffDiscount() {
$this->total -= ($this->total * ($this->discount/100)) ;
}
public function voidL() {
$this->total -= $this->lastamount;
}
}
Below is my normal code
include 'cashRegister.php';
$me = new cashRegister("Mg", 20);
$l = new cashRegister("ll", 50);
echo $me->inventory;
$me->scan("eggs", 2);
$me->scan("eggs", 1);
$me->scan("news", 1);
//$me->staffDiscount();
echo $me->inventory;
//echo $l->inventory;
//echo $me->total;
When you create a new instance of a class (that happens whenever you use the keyword new) it will create a brand new kind of 'copy' or 'instance' of that class. So, when you subtract the inventory amount, you are only subtracting from that instance.
PHP has the keyword static that will change the public instance variable of $inventory into a kind of shared variable between all instances of that class.
Update it from public to static to look like this:
public static $inventory = 10;
But you also need several other changes because you cannot reference a static variable in the same way as an instance variable.
Basically you need to change $this-> to self:: in your inventory method:
public function inventory($quantity) {
self::$inventory -= $quantity;
}
Then when you reference the static variable from the instance variable you need to access it like this:
echo $me::$inventory;
Your final code would look like this:
<?
class cashRegister {
public $total = 0;
public $name;
public $discount;
public $lastamount;
public static $inventory = 10;
public function __construct($name, $discount) {
$this->name = $name;
$this->discount = $discount;
}
public function add($itemCost) {
$this->total += $itemCost;
$this->lastamount = $itemCost;
}
public function scan($item, $quantity) {
switch ($item) {
case "eggs" :
$this->add ( 1 * $quantity);
$this->inventory($quantity);
break;
case "news" :
$this->add(2 * $quantity);
$this->inventory($quantity);
}
//$this->inventory -= $quantity;
}
public function inventory($quantity) {
self::$inventory -= $quantity;
}
public function staffDiscount() {
$this->total -= ($this->total * ($this->discount/100)) ;
}
public function voidL() {
$this->total -= $this->lastamount;
}
}
And when you call it:
$me = new cashRegister("Mg", 20);
$l = new cashRegister("ll", 50);
echo $me::$inventory;
echo "<br>";
$me->scan("eggs", 2);
$me->scan("eggs", 1);
$me->scan("news", 1);
//$me->staffDiscount();
echo $me::$inventory;
//echo $l->inventory;
//echo $me->total;
Here is an updated class that gives you a more extended idea of how you can use objects.
Instead of just an inventory class, it breaks down an item into an individual class and object that you can use.
When an item is scanned it loops through the inventory items and if there is not enough of that item in stock it will return false - in a real world scenario, you would probably handle that error differently but for this case it is okay. You might add a method called 'isItemInStock()' to the Inventory class that will check if it is available first.
So now that the inventory is an object its instance is shared between the other objects as well as the items that are in stock. Instead of adding/subtracting the totals during the scan process there is a getTotal() method that will recalculate the total with the discount.
<?
class Item {
public $name;
public $cost;
public $quantity;
public function __construct($name, $cost, $quantity=null) {
$this->name = $name;
$this->cost = $cost;
$this->quantity = $quantity;
}
}
class Inventory
{
public $items = array();
public function __construct()
{
}
public function add($item) {
$this->items[] = $item;
}
}
class CashRegister {
public $name;
public $discount;
public $inventory;
public $items = array();
public function __construct($name, $discount, $inventory) {
$this->name = $name;
$this->discount = $discount;
$this->inventory = $inventory;
}
public function add($item) {
$this->items[] = $item;
}
public function scan( $name, $qty ) {
foreach ($this->inventory->items as $key => $item) {
if ($item->name==$name) {
if (($item->quantity-$qty)>=0) {
$this->inventory->items[$key]->quantity -= $qty;
$this->add( new Item($item->name, $item->cost, $qty) );
return true;
} else {
// Not added, not enough
return false;
}
}
}
// Invalid item
return false;
}
public function getTotal() {
$total = 0;
foreach ($this->items as $item) {
$total += $item->cost*$item->quantity;
}
$discount = ((100-$this->discount)/100);
echo "Discount total: $discount\n";
return $total - $discount;
}
}
$inventory = new Inventory();
$inventory->add( new Item('eggs', 1, 20) );
$inventory->add( new Item('news', 2, 50) );
$cb1 = new CashRegister(1, 20, $inventory );
echo "<pre>\n";
echo "Scanning 5 eggs\n";
$cb1->scan( 'eggs', 5);
foreach ($inventory->items as $item) {
echo $item->name . ': '. $item->quantity." in stock\n";
}
echo "Scanning 6 news\n";
$cb1->scan( 'news', 5);
foreach ($inventory->items as $item) {
echo $item->name . ': '. $item->quantity." in stock\n";
}
$cb2 = new CashRegister(2, 30, $inventory );
echo "Scanning 3 eggs\n";
$cb2->scan('eggs', 3);
foreach ($inventory->items as $item) {
echo $item->name . ': '. $item->quantity." in stock\n";
}
echo "Cash Register 1 Total: " . $cb1->getTotal() . "\n";
echo "Cash Register 2 Total: " . $cb2->getTotal() . "\n";
I would define your inventory separately and add it to your cash register invocation.
class Inventory
{
public $eggs;
public $news;
public function __construct($eggs = 10, $news = 10)
{
$this->eggs = $eggs;
$this->news = $news;
}
}
You would need to modify your CashRegister class to use the properties of the object rather than just modifying the inventory property, and accept the inventory as an argument.
class CashRegister
{
// ...
protected $inventory;
public function __construct($inventory, name, $discount)
{
$this->inventory = $inventory;
$this->name = $name;
$this->discount = $discount;
}
// ...
public function scan($item, $quantity)
{
switch ($item) {
case "eggs" :
$this->add ( 1 * $quantity);
$this->inventory($item, $quantity);
break;
case "news" :
$this->add(2 * $quantity);
$this->inventory($item, $quantity);
}
}
protected function inventory($item, $quantity)
{
$this->inventory->$item -= $quantity;
}
// ...
}
Then you can do something like this:
$inventory = new Inventory;
$me = new CashRegister($inventory, 'mg', 20);
$l = new CashRegister($inventory, 'l', 50);
// ...
Because objects are always passed by reference, your inventory object is now in sync between both registers, and the changes made in either will affect the available inventory.
I am creating a kind of shopping cart for a very specific purpose, and I have create two basic classes. The one class is made to describe a product in the cart, and the other class is the cart.
My CartItem class looks like that:
class CartItem
{
private $id = null; // This is the product id
private $qty = 0; // This is the product Quantity
private $price = 0; // This is the product price
private $name = ''; // This is the product name
private $options = array(); // This array contains the product options
private $rowid = null; // This is the product id in the cart
private $subtotal = 0; // This is the product sub total
public function __construct(
$id = null,
$qty = null,
$price = null,
$name = null,
$options = array()
)
{
$this->id = $id;
$this->qty = (float)$qty;
$this->price = (float)$price;
$this->name = $name;
$this->options = $options;
}
public function __get($name)
{
return $this->{$name};
}
...
public function setQty($qty = 0)
{
$this->qty = (float)$qty;
return $this->qty;
}
...
}
and my Cart class is the following:
class Cart
{
protected $cart_contents = array();
protected $cart = null;
protected function __construct()
{
$this->cart = new SessionContainer('cart_contents');
$this->cart_contents = $this->cart->offsetGet('contents');
if(count($this->cart_contents) <= 2)
{
$this->cart_contents = array(
'cart_total' => 0,
'total_items' => 0
);
}
}
public function insert(CartItem $item)
{
$save_cart = false;
if(($rowid = $this->_insert($item)))
{
$save_cart = true;
}
if($save_cart === true)
{
$this->_save_cart();
return isset($rowid) ? $rowid : true;
}
return false;
}
protected function _insert(CDOCartItem $item)
{
if($item->qty == 0)
{
return false;
}
if(is_array($item->options) && count($item->options) > 0)
{
$rowid = md5($item->id . serialize($item->options));
}
else
{
$rowid = md5($item->id);
}
$old_quantity = isset($this->cart_contents[$rowid]->qty) ? $this->cart_contents[$rowid]->qty : 0;
$item->setRowId($rowid);
$item->setQty($item->qty + $old_quantity);
$this->cart_contents[$rowid] = $item;
return $rowid;
}
public function update(CDOCartItem $item)
{
$save_cart = false;
if($this->_update($item) === true)
{
$save_cart = true;
}
if($save_cart === true)
{
$this->_save_cart();
return true;
}
return false;
}
protected function _update(CartItem $item)
{
echo "Is this empty : " . empty($item->qty) . " : " . $item->qty;
if(empty($item->qty) || empty($item->rowid) || !isset($this->cart_contents[$item->rowid]))
{
return false;
}
$item->setQty((float)$item->qty);
if($item->qty <= 0)
{
unset($this->cart_contents[$item->rowid]);
}
else
{
$this->cart_contents[$item->rowid]->qty = $item->qty;
}
return true;
}
}
Then I try to play with this structure:
$item = new CartItem('SKU-12321', 12, 47.82, 'Name');
$cart = Cart::Instance(); // I have apply the singleton patternt in my local files
$itemRID = $cart->insert($item);
$newItem = $cart->get_item($itemRID); // This method return the object based on ID and 100% works in my code
$newItem->setQty(25);
$cart->update($newItem);
But the problem is that I am getting the following result:
Is it empty : 1 : 25
The above line is printed in the Cart Class in the update method.
As you can see, I am testing if the $item->qty is empty, and the test returns true, and in the same value I am echoing the current item quanity that it is 25 so, the actual property it is not empty.
Am I doing something wrong ? In PHP Documentation they are describing that the function empty can be used to test for empty or null values in variables, but I am not sure if that works in properties.
Can somebody to help me please ?
I think the problem comes from your CartItem::__get(). I explain: $qty is private, so a empty($item->qty) returns true because it is not accessible outside the element, but when you access it with just $item->qty, the variable will be considered as unexisting (because it is private) so the __get() method will be called and will return the right value because you access it within the class.
Hi i'm new to PHP and have below problem. i have written below codes to add data in to the array, now i need to see the added data, please tell me how to do it.
class ShoppingCart
{
private $items = array();
private $n_items = 0;
function addItem( Item $item )
{
$this->items[] = $item;
$this->n_items = $this->n_items + 1;
//print_r (array_values($this->items));
echo "item $this->items added sussesfully";
}
}
and
class Item {
protected $name;
protected $price;
public function __construct($name, $price) {
$this->name = $name;
$this->price = $price;
}
public function getName() {
echo "item is $this->name";
return $this->name;
}
public function getPrice() {
return $this->price;
}
}
and
require_once('AddingMachine.php');
require_once('item.php');
//$arrayofnumbers = array(100,200);
$objectname = new ShoppingCart();
$objectname->addItem(new Item('My Super Cool Toy', 10.99));
Thanks
Since $items is a private property you will need to create a new method on the ShoppingCart class
public function getItems()
{
return $this->items;
}
And then retrieve the $items array by calling the new method
$objectname = new ShoppingCart();
$items = $objectname->getItems();
var_dump($items);
I have below array result
Array ( [0] => Item Object ( [name:protected] => My Super Cool Toy [price:protected] => 10.99 ) )
I need to get [name:protected] => My Super Cool Toy from this array.
Please tell me how to get it,
I will paste my classes below
class ShoppingCart
{
private $items = array();
private $n_items = 0;
function addItem( Item $item )
{
$this->items[] = $item;
$this->n_items = $this->n_items + 1;
print_r($this->items);
}
}
and
class Item {
protected $name;
protected $price;
public function __construct($name, $price) {
$this->name = $name;
$this->price = $price;
}
public function getName() {
echo "item is $this->name";
return $this->name;
}
public function getPrice() {
return $this->price;
}
}
and
require_once('AddingMachine.php');
require_once('item.php');
//$arrayofnumbers = array(100,200);
$objectname = new ShoppingCart();
$objectname->addItem(new Item('My Super Cool Toy', 10.99));
$obname = new Item($items,44);
$obname->getName();
Thanks
If I got it correctly, you got this array in ShoppingCart class, in method addItem, so to access it you just use corresponding getter method, e.g.:
$this->items[0]->getName();
You can try :
$objectname = new ShoppingCart();
$objectname->addItem(new Item('My Super Cool Toy', 10.99));
foreach ( $objectname->getItems() as $item ) {
echo $item->getName(), PHP_EOL;
}
Modified Class
class ShoppingCart {
private $items = array();
private $n_items = 0;
function addItem(Item $item) {
$this->items[] = $item;
$this->n_items = $this->n_items + 1;
}
function getItems($n = null) {
return $n === null ? $this->items : (isset($this->items[$n]) ? : $this->items[$n]);
}
}