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.
Related
I am creating an API and I want to add extra column in the result of pagination query. For example I have price and discount in my database. I want to send discounted_price column with result set.
Here is what I have tried so far:
Controller:
$products = Products::latest()->paginate(10);
if (! empty($products)) {
$final_prod = [];
foreach ($products as $product) {
$final_prod[] = $product->asFilterJson();
}
$data['products'] = $final_prod;
$data['status'] = 200;
} else {
$data['error'] = "No product available";
}
and in my Products model I have
public function asFilterJson() {
$json = [];
$json['id'] = $this->id;
$json['title'] = $this->title;
$json['category_id'] = $this->category_id;
$json['price'] = $this->price;
$json['description'] = $this->description;
$json['quantity'] = $this->quantity;
$json['discount'] = $this->discount;
$json['type_id'] = $this->type_id;
$json['created_by_id'] = $this->created_by_id;
$json['created_at'] = $this->created_at;
$json['updated_at'] = $this->updated_at;
if($this->type_id == self::ITEM_SPECIAL) {
$json['discounted_price'] = ($this->discount * $this->price) / 100; }
return $json;
}
It works fine but it removes the pagination.
you can add key and value in collection object by using map method
$products = Products::latest()->paginate(10);
$itemSpecial = self::ITEM_SPECIAL; //pass variable in closure by using use
$products->map(function($item) use ($itemSpecial) {
if($item->type_id == $itemSpecial) {
$item->discounted_price = ($item->discount * $item->price) / 100;
}
return $item;
});
you can used condition also in clourse
In Controller
public function index() {
$products = Products::latest()->paginate(10);
if (! empty($products)) {
$final_prod = [];
foreach ($products as $product) {
$final_prod[] = $this->asFilterJson($product);
}
return response()->json(['status'=>'200','message'=>'Product list ','data'=>$final_prod]);
} else {
return response()->json(['status'=>'200','message'=>'No product available','data'=>[]]);
}
}
// function for extra column add
static function asFilterJson($product){
$value['discounted_price'] = ($value['discount'] * $value['price']) / 100;
return $value;
}
You can define new mutator in your model.
public function getDiscountedPriceAttribute()
{
return ($this->discount * $this->price) / 100;
}
After than, you can use it as $this->discountedPrice
I'm using Woocommerce with my Wordpress theme. The website is selling services. The template developer support is dead, they say woocommerce compatibility but there is small bug I need to find the fix myself but I don't know what to do.
When the client tries to add credit to his account he selects the value and goes to next screen where woocommerce payment gateways are shown, they are listed but 'Pay' button its not there. When I look into Wordpress wp-content debug log I got this errors:
[23-Jul-2018 10:15:58 UTC] PHP Strict Standards: Declaration of ET_WC_Order::get_total() should be compatible with WC_Abstract_Order::get_total($context = 'view') in /home/admin/public_html/mysite.com/wp-content/themes/mysite.com/includes/aecore/wc_integration/payment/ET_WC_Order.php on line 3
[23-Jul-2018 10:15:58 UTC] PHP Strict Standards: Declaration of ET_WC_Package::get_sku() should be compatible with WC_Product::get_sku($context = 'view') in /home/admin/public_html/mysite.com/wp-content/themes/mysite.com/includes/aecore/wc_integration/payment/ET_WC_Package.php on line 4
ET_WC_Order.php content:
<?php if(class_exists("WC_Abstract_Order")) {
class ET_WC_Order extends WC_Abstract_Order
{
protected $etOrder;
protected $cancel_url = "";
protected $received_url = "";
public function __construct($order = '')
{
$this->post_type = 'order';
$this->prices_include_tax = get_option('woocommerce_prices_include_tax') == 'yes' ? true : false;
$this->tax_display_cart = get_option('woocommerce_tax_display_cart');
$this->display_totals_ex_tax = $this->tax_display_cart == 'excl' ? true : false;
$this->display_cart_ex_tax = $this->tax_display_cart == 'excl' ? true : false;
$this->init($order);
}
public function get_refunds()
{
return array();
}
public function get_total_refunded()
{
return 0;
}
/**
* Init
*
* #param int|object|WC_Order $order
*/
protected function init($order)
{
if (is_numeric($order)) {
$this->id = absint($order);
$this->post = get_post($order);
$this->get_order($this->id);
} elseif ($order instanceof ET_WC_Order) {
$this->id = absint($order->id);
$this->ID = absint($order->id);
$this->post = $order->post;
$this->etOrder = $order->etOrder;
$this->populate($order->etOrder);
} elseif ($order instanceof AE_Order) {
$payData = $order->generate_data_to_pay();
$order->ID = $payData["ID"];
$this->etOrder = $order;
$this->populate($order);
// Billing email cam default to user if set
if (empty($this->billing_email) && !empty($this->customer_user)) {
$user = get_user_by('id', $this->customer_user);
$this->billing_email = $user->user_email;
}
} elseif ($order instanceof WP_Post || isset($order->ID)) {
$this->id = absint($order->ID);
$this->post = $order;
$this->get_order($this->id);
}
}
public function get_order($id = 0)
{
if (!$id) {
return false;
}
$this->etOrder = new AE_Order($id);
if ($this->etOrder) {
$payData = $this->etOrder->generate_data_to_pay();
$this->etOrder->ID = $payData["ID"];
$this->populate($this->etOrder);
return true;
}
return false;
}
/**
* Populate the order, like convert method
*
* #param mixed $result
*/
public function populate($result)
{
$orderData = $result->get_order_data();
// Standard post data
$this->id = $result->ID;
$this->order_date = $orderData['created_date'];
$this->modified_date = $orderData['created_date'];
$this->customer_message = '';
$this->customer_note = '';
$this->post_status = $orderData['status'];
// Billing email cam default to user if set
if (empty($this->billing_email) && !empty($this->customer_user)) {
$user = get_user_by('id', $this->customer_user);
$this->billing_email = $user->user_email;
}
$this->cancel_url = et_get_page_link('process-payment', array('paymentType' => $orderData['payment']));
$this->received_url = et_get_page_link('process-payment', array('paymentType' => $orderData['payment']));
}
public function get_shipping_address()
{
return "";
}
/**
* Get item of order
*
* #param string $type
* #return array
*/
public function get_items($type = '')
{
if (empty($type)) {
$type = array('line_item');
}
if (!is_array($type)) {
$type = array($type);
}
$type = array_map('esc_attr', $type);
$items = array();
if (in_array('line_item', $type)) {
$orderData = $this->etOrder->get_order_data();
if (isset($orderData["products"])) {
$index = 0;
foreach ($orderData["products"] as $id => $product) {
$items[$index]['name'] = $product['NAME'];
$items[$index]['product_id'] = $product['ID'];
$items[$index]['type'] = "line_item";
$items[$index]['qty'] = $product['QTY'];
$items[$index]['tax_class'] = '';
$items[$index]['line_subtotal'] = $product['AMT'];
$items[$index]['line_subtotal_tax'] = '0';
$items[$index]['item_meta'] = array();
$index++;
}
}
}
return $items;
}
/**
* Get total of order
* #author : Nguyễn Văn Được
* #return mixed
*/
public function get_total()
{
$orderData = $this->etOrder->get_order_data();
$total = $orderData["total"];
return $total;
}
/**
* Get order currency
* #author : Nguyễn Văn Được
* #return mixed
*/
public function get_order_currency()
{
$orderData = $this->etOrder->get_order_data();
return $orderData["currency"];
}
/**
* Get products from product item
* #author : Nguyễn Văn Được
*
* #param mixed $item
*
* #return bool|\ET_WC_Package
*/
public function get_product_from_item($item)
{
if (!empty($item['product_id'])) {
$_product = new ET_WC_Package($item['product_id']);
} else {
$_product = false;
}
return $_product;
}
public function get_checkout_order_received_url()
{
return $this->received_url;
}
public function set_checkout_order_received_url($received_url)
{
$this->received_url = $received_url;
}
public function get_cancel_order_url($redirect = '')
{
return $this->cancel_url;
}
public function set_cancel_order_url($cancel_url)
{
$this->cancel_url = $cancel_url;
}
/**
* Update order status
*
* #param string $new_status
* #param string $note
*/
public function update_status($new_status, $note = '', $manual = false)
{
if (!$this->id) {
return;
}
// Standardise status names.
$new_status = 'wc-' === substr($new_status, 0, 3) ? substr($new_status, 3) : $new_status;
$old_status = $this->get_status();
switch (strtoupper($new_status)) {
case 'COMPLETED':
case 'PUBLISH':
$this->post_status = 'publish';
break;
case 'PROCESSING' :
case 'ON-HOLD':
$this->post_status = 'pending';
break;
case 'CANCELLED' :
$this->post_status = 'draft';
break;
default:
$this->post_status = 'draft';
break;
}
$this->etOrder->post_status = $this->post_status;
$log = new WC_Logger();
$log->add('paypal', "Our Debug : " . $this->post_status);
wp_update_post(array('ID' => $this->etOrder->ID, 'post_status' => $this->post_status));
}
public function needs_shipping_address()
{
return false;
}
public function is_editable()
{
return parent::is_editable(); // TODO: Change the autogenerated stub
}
public function get_qty_refunded_for_item($item_id, $item_type = 'line_item')
{
$qty = 0;
return $qty;
}
public function get_total_refunded_for_item($item_id, $item_type = 'line_item')
{
$total = 0;
return $total * -1;
}
}
}
ET_WC_Package.php content:
<?php
if(class_exists("WooCommerce")) {
class ET_WC_Package extends WC_Product
{
protected $etPaynentPackage;
function __construct($product, $arg = array())
{
$this->product_type = 'pack';
parent::__construct($product);
}
public function get_sku()
{
return $this->post->ID;
}
public function is_virtual()
{
return true;
}
public function needs_shipping()
{
return false;
}
public function get_permalink() {
return get_permalink( $this->id );
}
}
}
PHP Strict Standards: Declaration of ET_WC_Order::get_total() should
be compatible with WC_Abstract_Order::get_total($context = 'view')
Change the get_total() function in ET_WC_Order.php to be
public function get_total($context = 'view')
{
$orderData = $this->etOrder->get_order_data();
$total = $orderData["total"];
return $total;
}
PHP Strict Standards: Declaration of ET_WC_Package::get_sku() should
be compatible with WC_Product::get_sku($context = 'view')
Change the get_sku() function in ET_WC_Package.php to be
public function get_sku($context = 'view')
{
return $this->post->ID;
}
I'm trying to pass an instance of my Generator class to another class to use some of the variables. The Generator class instance works fine but when i passed it to another (SelectStrategy) class it seems it is not passing the variable at all. I'm not sure what I'm doing wrong - I used var_dump on the called function to check what it gives me but it's just blank.
Function
class Generator
{
//properties for self
private $s_charge;
public $connection;
public $task_priority;
public $fog_mode = true;
public $nodes = array();
public $type;
public function generateNodesSpecs() {
$node = array();
for ($i = 0; $i < 100; $i++) {
$charge1 = mt_rand(30,100);
$node['charge'] = $charge1;
//array_push($node, $charge1);
$hops = mt_rand(0,4);
$node['hops'] = $hops;
//array_push($node, $hops);
$resource1 = mt_rand(0,100);
if ($resource1 <= 50) {
if ($resource1 <=10){
$node['connection'] = '4G';
//array_push($node, '4G');
}
else {
$node['connection'] = '3G';
//array_push($node, '3G');
}
}
else if ($resource1 > 50 && $resource1 <= 60) {
$node['connection'] = 'WiFi';
//array_push($node, 'WiFi');
}
else {
}
$resource2 = mt_rand(0,100);
if ($resource2 <=60) {
$node['additional'] = 'CPU';
//array_push($node, 'CPU');
}
else {
$node['additional'] = 'none';
}
$this->nodes[] = $node;
//array_push($nodes, $node);
unset($node);
}
//compare which get the resources
//var_dump($this->nodes[0]);
}
class SelectStrategy {
//take in generator class instance
private $generator;
private $priority;
private $size;
private $slaves = array();
private $found_slave = null; //will hold item with max val;
public function __construct($generator) {
$this->generator = $generator;
}
private function selectSlaves() {
$max = -9999999; //will hold max val
foreach($this->generator->nodes as $k=>$v)
{
if($v['charge']>$max)
{
$max = $v['charge'];
$this->found_slave = $v;
}
}
var_dump($this->found_slave);
}
}
And classes/function calls
$generator = new Generator();
$generator->generateNodesSpecs();
$select_strategy = new SelectStrategy($generator);
$select_strategy->selectSlaves();
The $this->generator->nodes is a 2D array
global $generator;
in every function of SelectSlave should do it
I am trying to implement a linked list using PHP.
I have completed some part of it, however, I am not sure if my code is correct or not.
Could you please advise how to add/delete a specific node at specified index?
Please refer to the below codes: (3 files in total)
1) [ListNode.class.php]
The structure of node I defined:
<?php
class ListNode
{
protected $next; // Next node in the list
protected $value; // Value of the node
// Constructor
// Input: Value of the node
public function __construct($value)
{
$this->value = $value;
$this->next = NULL;
}
public function __get($name)
{
return $this->$name;
}
public function __set($name, $value)
{
$this->$name = $value;
}
// Return the node as string
public function toString()
{
return $this->value . "\n";
}
}
2) [LinkList.class.php]
The linked list and the operations that I am not finished with:
<?php
require('ListNode.class.php');
class LinkedList
{
protected $first; // First node of the list
protected $last; // Last node of the list
protected $count; // Total numbers of nodes in the list
// Constructor
// Input: Array of values (Optional)
public function __construct($values = array())
{
$this->first = null;
$this->last = null;
$this->count = 0;
foreach ($values as $value) {
$this->add($value);
}
}
public function isEmpty()
if ($this->sizeOf() !== 0)
return ($this->first == NULL);
}
// Add a node at the beginning of the list
public function add($value)
{
$link = new ListNode($value);
$link->next = $this->first;
$this->first = &$link;
if($this->last == NULL)
$this->last = &$link;
$this->count++;
}
// Add a node at the specified index
public function addAtIndex($value, $index)
{
}
// Remove a node at the end of the list
public function remove()
{
if($this->first != NULL)
{
if($this->first->next == NULL)
{
$this->first == NULL;
$this->cout--;
}
else
{
$previous = $this->first;
$current = $this->first->next;
while($current->next != NULL)
{
$previous = $current;
$current = $current->next;
$previous->next = NULL;
$this->count--;
}
}
// Remove a node at the specified index
public function removeAtIndex($index)
{
}
// Return the value of the first node
public function getNode()
{
}
// Return the value of the node at the specified index
public function getNodeAtIndex($index)
{
if($index <= $this->count)
{
$current = $this->firstNode;
$pos = 1;
while($pos != $index)
{
if($current->next == NULL)
return null;
else
$current = $current->next;
$pos++;
}
return $current->value;
}
else
return NULL;
}
// Return the number of nodes
public function sizeOf()
{
return $this->count;
}
// Return the list as string
public function toString()
{
$list = "";
$node = $this->first;
while ($node != null) {
$list .= $node->toString();
$node = $node->next;
}
return $list;
}
}
If you need a linked list, why not use the Standard PHP Library? There you have SplDoublyLinkedList with all the functionality that you need:
add node at index: offsetSet()
delete node at index: offsetUnset()
Those methods are part of the implemented ArrayAccess interface, this means you don't have to call them directly but can do something like that:
$list = new SplDoublyLinkedList;
$list->push('item 1');
$list->push('item 2');
$list->push('item 3');
echo $list[1];
unset($list[1]);
foreach($list as $index => $value) {
echo "\n$index: $value";
}
Output:
item 2
0: item 1
1: item 3
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>";
?>