Refactor order and order item management: add cache invalidation, improve object change tracking, and enhance asArray conversion with caching and expiration support.
This commit is contained in:
@@ -90,10 +90,19 @@ class collected_order_invoices_o extends db
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the invoice collection as an array
|
||||
* @throws ApiErrorException If the payment method is Stripe and the request fails
|
||||
* @throws Exception If the request was not successful
|
||||
*/
|
||||
public function asArray(): array
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Check if the object is cached
|
||||
$cached = self::getCached('asArray', $this->id);
|
||||
if ($cached !== null) {
|
||||
return (array)$cached;
|
||||
}
|
||||
$tmp = [
|
||||
'id' => (int)$this->id,
|
||||
'customer_number' => (int)$this->customer_number->value(),
|
||||
@@ -130,6 +139,9 @@ class collected_order_invoices_o extends db
|
||||
]);
|
||||
$tmp['stripe'] = $stripe_details;
|
||||
}
|
||||
// Cache the result
|
||||
self::cache('asArray', $tmp, $this->id);
|
||||
self::setCachedExpiration('asArray', self::$asArrayCacheExpiration, $this->id);
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
@@ -141,6 +153,8 @@ class collected_order_invoices_o extends db
|
||||
*/
|
||||
public function getOrders(bool $count = false): array|int
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
$orders = new orders_o();
|
||||
$order_ids = $orders->getFieldsWhere(
|
||||
[
|
||||
@@ -542,7 +556,8 @@ class collected_order_invoices_o extends db
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
//TODO: Add cache invalidation
|
||||
// Invalidate the cache, so the next time the object is requested, it will be fetched from the database
|
||||
self::deleteCached('asArray', $this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -609,6 +624,8 @@ class collected_order_invoices_o extends db
|
||||
foreach ( $orders as $order ) {
|
||||
self::addInvoiceToDraft($order['id'], true, $draft_id, $currency);
|
||||
}
|
||||
// Object changed
|
||||
self::objectChanged();
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -837,6 +854,8 @@ class collected_order_invoices_o extends db
|
||||
// Set the order to the new invoice collection
|
||||
$order_object->invoice_collection_id->set($tmp->id);
|
||||
}
|
||||
// Invalidate the cache for the invoice collection
|
||||
$this->objectChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -912,6 +931,7 @@ class collected_order_invoices_o extends db
|
||||
$transaction->invoice_collection_id->set($this->id);
|
||||
$transaction->created_at->set(self::getFirstDayOfMonth($this->created_at->value()));
|
||||
$transaction->objectChanged();
|
||||
$this->objectChanged();
|
||||
// Add the vehicle subscriptions to the transaction
|
||||
$order_items_o = new order_items_o();
|
||||
foreach ( $vehicle_array as $vehicle ) {
|
||||
@@ -974,6 +994,7 @@ class collected_order_invoices_o extends db
|
||||
$order_item_object->requireSelected();
|
||||
$order_item_object->include_in_invoice->set(0);
|
||||
$order_item_object->price->set((int)self::getWashSubscriptionPrice((new products_o())->select((int)$order_item['product_id'])->price->value()) / 2);
|
||||
$order_item_object->objectChanged();
|
||||
}
|
||||
// Check if the order item product id is equal any of the vehicle subscription addons product id
|
||||
if (isset($vehicle_regs[$order['reg_1']]['addons'][$order_item['product_id']])) {
|
||||
@@ -999,10 +1020,13 @@ class collected_order_invoices_o extends db
|
||||
$order_item_object->requireSelected();
|
||||
$order_item_object->include_in_invoice->set(0);
|
||||
$order_item_object->price->set($tmp_subscription_price);
|
||||
$order_item_object->objectChanged();
|
||||
}
|
||||
}
|
||||
$order_object->objectChanged();
|
||||
}
|
||||
}
|
||||
$this->objectChanged();
|
||||
//print_r($vehicle_array);
|
||||
}
|
||||
|
||||
@@ -1034,6 +1058,8 @@ class collected_order_invoices_o extends db
|
||||
$order->requireSelected();
|
||||
$order->delete();
|
||||
}
|
||||
// Clear the cache for the invoice collection
|
||||
$this->objectChanged();
|
||||
}
|
||||
|
||||
private static function getFirstDayOfMonth(string $timestamp): string
|
||||
@@ -1137,7 +1163,10 @@ class collected_order_invoices_o extends db
|
||||
$order_item_object->requireSelected();
|
||||
$order_item_object->include_in_invoice->set(0);
|
||||
$order_item_object->price->set(0);
|
||||
$order_item_object->objectChanged();
|
||||
}
|
||||
}
|
||||
// Invalidate the cache for the invoice collection
|
||||
$this->objectChanged();
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class order_items_o extends db
|
||||
@@ -62,11 +63,6 @@ class order_items_o extends db
|
||||
$this->setTable('order_items');
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
// No need to invalidate the cache, since the order_items object is not cached
|
||||
}
|
||||
|
||||
public function getOrderItemById(int $id): order_items_o
|
||||
{
|
||||
global $db;
|
||||
@@ -113,11 +109,37 @@ class order_items_o extends db
|
||||
if ($related_item_id) {
|
||||
$this->related_item_id->set($related_item_id);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Inform the order object that a new item has been added
|
||||
$this->getOrder()->objectChanged();
|
||||
} catch (Exception $e) {
|
||||
$response->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function objectChanged(): void
|
||||
{
|
||||
// This method is called when the object is changed, to inform the order object
|
||||
// that an item has been added, edited or removed.
|
||||
// This is used to update the order total and other related properties.
|
||||
$order = $this->getOrder();
|
||||
$order->objectChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order object associated with this order item
|
||||
* @return orders_o The order object associated with this order item
|
||||
* @throws Exception If the order item is not selected
|
||||
* @throws Exception If no order is selected
|
||||
*/
|
||||
public function getOrder(): orders_o
|
||||
{
|
||||
self::requireSelected();
|
||||
return (new orders_o())->select($this->id);
|
||||
}
|
||||
|
||||
public function edit(int $id, int $order_id, int $product_id, string $reference, string $notes, int $cashier_id, int $price, int $quantity): void
|
||||
{
|
||||
global $db, $response;
|
||||
@@ -132,7 +154,9 @@ class order_items_o extends db
|
||||
|
||||
// Set the values of the object properties
|
||||
$this->getObjectProperties();
|
||||
} catch (\Exception $e) {
|
||||
// Inform the order object that an item has been edited
|
||||
$this->objectChanged();
|
||||
} catch (Exception $e) {
|
||||
$response->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -173,13 +197,17 @@ class order_items_o extends db
|
||||
if ($notes) {
|
||||
$this->notes->set($notes);
|
||||
}
|
||||
$this->objectChanged();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$response->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function removeOrderItem(int $id): void
|
||||
{
|
||||
// TODO: Implement delete() method instead
|
||||
@@ -187,6 +215,8 @@ class order_items_o extends db
|
||||
$this->id = $id;
|
||||
$sql = "DELETE FROM $this->table WHERE id = $this->id or related_item_id = $this->id";
|
||||
$db->query($sql);
|
||||
// Inform the order object that an item has been removed
|
||||
$this->getOrder()->objectChanged();
|
||||
}
|
||||
|
||||
public function getItemAsArray(): array
|
||||
@@ -236,7 +266,8 @@ class order_items_o extends db
|
||||
$db->query($sql);
|
||||
// Set the values of the object properties
|
||||
$this->getObjectProperties();
|
||||
} catch (\Exception $e) {
|
||||
$this->objectChanged();
|
||||
} catch (Exception $e) {
|
||||
$response->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ class orders_o extends db
|
||||
public object_property $wash_id; // The XL Vask Wash ID, if any
|
||||
public object_property $lane; // The lane used for the order, if any
|
||||
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
$this->setTable('orders');
|
||||
@@ -116,9 +117,49 @@ class orders_o extends db
|
||||
{
|
||||
// Set the deleted_at property to the current timestamp
|
||||
$this->deleted_at->set(date('Y-m-d H:i:s'));
|
||||
$this->objectChanged();
|
||||
// Save the object
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception If the order is not selected
|
||||
* This function is called when the order object is changed.
|
||||
*/
|
||||
public function objectChanged(): void
|
||||
{
|
||||
self::requireSelected();
|
||||
// Reset the cached object
|
||||
self::deleteCached('asArray', $this->id);
|
||||
// Inform the order collection that the order has changed
|
||||
$this->getOrderCollection()->objectChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order collection for the order
|
||||
* @return collected_order_invoices_o The order collection
|
||||
* @throws Exception If the order is not selected
|
||||
*/
|
||||
public function getOrderCollection(): collected_order_invoices_o
|
||||
{
|
||||
self::requireSelected();
|
||||
$order_collection = new collected_order_invoices_o();
|
||||
$order_collection->select($this->invoice_collection_id->value());
|
||||
if (!$order_collection->exists()) {
|
||||
throw new Exception('Order collection not found');
|
||||
}
|
||||
return $order_collection;
|
||||
}
|
||||
|
||||
public function exists(): bool
|
||||
{
|
||||
// Check if the id is greater than 0, and that the deleted_at property is null
|
||||
if ($this->id > 0) {
|
||||
$this->getObjectProperties();
|
||||
return $this->deleted_at->value() === null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function restore(): void
|
||||
{
|
||||
// Set the deleted_at property to null
|
||||
@@ -192,16 +233,6 @@ class orders_o extends db
|
||||
$this->{$data['field']}->set($data['value']);
|
||||
}
|
||||
|
||||
public function exists(): bool
|
||||
{
|
||||
// Check if the id is greater than 0, and that the deleted_at property is null
|
||||
if ($this->id > 0) {
|
||||
$this->getObjectProperties();
|
||||
return $this->deleted_at->value() === null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the order as completed
|
||||
* @throws Exception If the order is not selected
|
||||
@@ -223,11 +254,6 @@ class orders_o extends db
|
||||
$this->objectChanged();
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
// Since the orders object is not cached, there is no need to invalidate the cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order by invoice id
|
||||
* @param int $invoiceId
|
||||
@@ -427,22 +453,6 @@ class orders_o extends db
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order collection for the order
|
||||
* @return collected_order_invoices_o The order collection
|
||||
* @throws Exception If the order is not selected
|
||||
*/
|
||||
public function getOrderCollection(): collected_order_invoices_o
|
||||
{
|
||||
self::requireSelected();
|
||||
$order_collection = new collected_order_invoices_o();
|
||||
$order_collection->select($this->invoice_collection_id->value());
|
||||
if (!$order_collection->exists()) {
|
||||
throw new Exception('Order collection not found');
|
||||
}
|
||||
return $order_collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the wash subscription transactions for a customer
|
||||
* @throws Exception If something goes wrong
|
||||
@@ -473,9 +483,22 @@ class orders_o extends db
|
||||
);
|
||||
}
|
||||
|
||||
public function asArray(): array
|
||||
/**
|
||||
* @return array The order as an array
|
||||
* @throws Exception
|
||||
* Convert the order object to an array
|
||||
*/
|
||||
public function asArray(bool $skipCache = false): array
|
||||
{
|
||||
return [
|
||||
self::requireSelected();
|
||||
if (!$skipCache) {
|
||||
// Check if the object is cached
|
||||
$cached = self::getCached('asArray', $this->id);
|
||||
if ($cached) {
|
||||
return (array)$cached;
|
||||
}
|
||||
}
|
||||
$tmp = [
|
||||
'id' => $this->id,
|
||||
'customer_id' => (int)$this->customer_id->value(),
|
||||
'cashier_id' => (int)$this->cashier_id->value(),
|
||||
@@ -495,6 +518,10 @@ class orders_o extends db
|
||||
'lane' => $this->lane->value(),
|
||||
'closed_at' => (int)$this->invoice_collection_id->value() ? (new collected_order_invoices_o())->select((int)$this->invoice_collection_id->value())->closed_at->value() : null,
|
||||
];
|
||||
// Cache the object
|
||||
self::cache('asArray', $tmp, $this->id);
|
||||
self::setCachedExpiration('asArray', self::$asArrayCacheExpiration, $this->id);
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
public function getNetAmount(): float
|
||||
|
||||
@@ -41,7 +41,7 @@ class ordersRoute
|
||||
// Log the incident
|
||||
(new logs_o())->add('orders', 'global', 1, $user->id, 'LIST_ORDERS', 'Successfully listed orders');
|
||||
// Create economic_module_orders object
|
||||
$economic_module_orders = new economic_module_orders();
|
||||
//$economic_module_orders = new economic_module_orders();
|
||||
$orders = new orders_o();
|
||||
if (!$restrict_only_own) {
|
||||
$department_ids = $user->getGroup()->getDepartments();
|
||||
@@ -216,7 +216,8 @@ class ordersRoute
|
||||
if (isset($data['created_at'])) {
|
||||
$order->created_at->set($data['created_at']);
|
||||
}
|
||||
// If the department ID is set, validate it
|
||||
// Void any cached key for the order
|
||||
$order->objectChanged();
|
||||
// Log the incident
|
||||
(new logs_o())->add('orders', $order->department_id->value(), 1, $user->id, 'EDIT_ORDER', 'Successfully updated an order (ID: ' . $data['id'] . ')');
|
||||
// Return a success message
|
||||
|
||||
@@ -44,10 +44,11 @@ use objects\users_o;
|
||||
|
||||
trait db_object_t
|
||||
{
|
||||
public int $id; // The id of the object in the database
|
||||
private string $table; // The table of the objects in the database (e.g. users)
|
||||
private array $searchableFields = []; // The fields to search in the database (e.g. ['name', 'email']). If empty, all fields will be searched
|
||||
private array $whereClauses = []; // The where clauses to add to the pagination query
|
||||
public static int $asArrayCacheExpiration = 600; // The id of the object in the database
|
||||
public int $id; // The table of the objects in the database (e.g. users)
|
||||
private string $table; // The fields to search in the database (e.g. ['name', 'email']). If empty, all fields will be searched
|
||||
private array $searchableFields = []; // The where clauses to add to the pagination query
|
||||
private array $whereClauses = []; // The cache expiration time for the asArray function, in seconds. This is used to cache the result of the asArray function to improve performance. Default is 10 minutes (600 seconds).
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -744,6 +745,40 @@ trait db_object_t
|
||||
redis->set($this->table . '_' . $objectId . '_' . $key, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cached object expiration time
|
||||
* @param string $key The key to set the cached object expiration time
|
||||
* @param int $seconds The number of seconds to set the cached object expiration time
|
||||
* @param null $objectId
|
||||
* @return void
|
||||
*/
|
||||
public function setCachedExpiration(string $key, int $seconds, $objectId = null): void
|
||||
{
|
||||
// If the object id is not set, use the object id
|
||||
if (!$objectId) {
|
||||
$objectId = $this->id;
|
||||
}
|
||||
// Set the expiration time for the cached data
|
||||
redis->expire($this->table . '_' . $objectId . '_' . $key, $seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a cached object key (redis key)
|
||||
* @param string $key The key to get the cached object
|
||||
* @return string The cached object key
|
||||
* @throws Exception If the object is not selected, it throws an exception
|
||||
*/
|
||||
public function getCachedKey(string $key, $objectId = null): string
|
||||
{
|
||||
self::requireSelected();
|
||||
// If the object id is not set, use the object id
|
||||
if (!$objectId) {
|
||||
$objectId = $this->id;
|
||||
}
|
||||
// Return the cached data key
|
||||
return $this->table . '_' . $objectId . '_' . $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached object
|
||||
* @param string $key The key to get the cached object
|
||||
|
||||
Reference in New Issue
Block a user