huesos/mirzaev/arming_bot/system/controllers/order.php

478 lines
12 KiB
PHP
Executable File

<?php
declare(strict_types=1);
namespace mirzaev\arming_bot\controllers;
// Files of the project
use mirzaev\arming_bot\controllers\core,
mirzaev\arming_bot\models\cart as model,
mirzaev\arming_bot\models\product,
mirzaev\arming_bot\models\menu,
mirzaev\arming_bot\models\enumerations\language;
// Framework for PHP
use mirzaev\minimal\http\enumerations\content,
mirzaev\minimal\http\enumerations\status;
/**
* Controller of cart
*
* @package mirzaev\arming_bot\controllers
*
* @param model|null $cart Instance of the cart
* @param array $errors Registry of errors
*
* @method null index() HTML-document with shopping cart and delivery settings
* @method null product(int|string|null $identifier, ?string $type, int|string|null $amount) Change status of the product in the cart
* @method null summary() Information about products in the cart
*
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class cart extends core
{
/**
* Cart
*
* @var model|null $cart Instance of the cart
*/
protected readonly ?model $cart;
/**
* Errors
*
* @var array $errors Registry of errors
*/
protected array $errors = [
'session' => [],
'account' => [],
'menu' => [],
'cart' => []
];
/**
* Index
*
* HTML-document with shopping cart and delivery settings
*
* @param null
*/
public function index(): null
{
if (isset($menu)) {
//
} else {
// Not received ... menu
// Search for filters and write to the buffer of global variables of view templater
$this->view->menu = menu::_read(
return: 'MERGE(d, { name: d.name.@language })',
sort: 'd.style.order ASC, d.created DESC, d._key DESC',
amount: 4,
parameters: ['language' => $this->language->name],
errors: $this->errors['menu']
);
}
// Initializing the cart
$this->cart ??= $this->account?->cart() ?? $this->session?->cart();
// Initializing the cart data
$this->view->cart = [
'summary' => $this->cart?->summary(currency: $this->currency),
'products' => $this->cart?->products(language: $this->language, currency: $this->currency)
];
// Initializing types of avaiabld deliveries
$this->view->deliveries = [
'cdek' => [
'label' => 'CDEK'
]
];
if (str_contains($this->request->headers['accept'], content::json->value)) {
// Request for JSON response
// Sending response
$this->response
->start()
->clean()
->sse()
->json([
'main' => '',
'errors' => $this->errors
])
->validate($this->request)
?->body()
->end();
} else if (str_contains($this->request->headers['accept'], content::any->value)) {
// Request for any response
// Render page
$page = $this->view->render('cart/page.html', [
'h2' => $this->language === language::ru ? 'Корзина' : 'Cart' // @see https://git.mirzaev.sexy/mirzaev/huesos/issues/1
]);
// Sending response
$this->response
->start()
->clean()
->sse()
->write($page)
->validate($this->request)
?->body()
->end();
// Deinitializing rendered page
unset($page);
}
// Exit (success/fail)
return null;
}
/**
* Product
*
* Change status of the product in the cart
*
* @param int|string|null $identifier Product identifier
* @param string|null $type Action type (toggle, write, delete, set)
* @param int|string|null $amount Amount of actions with the product (for write, delete and differently used by set)
*
* @return null
*
* @todo
* 1. Add a limit on adding products to the cart based on the number of products in stock
*/
public function product(
int|string|null $identifier = null,
?string $type = null,
int|string|null $amount = null
): null {
if (str_contains($this->request->headers['accept'], content::json->value)) {
// Request for JSON response
// Declaring buffer with amount of the product in the cart
$cart = 0;
// Validating @todo add throwing errors
if (isset($identifier) && preg_match('/[\d]+/', urldecode($identifier), $matches)) $identifier = (int) $matches[0];
else unset($identifier);
if (isset($identifier)) {
// Received and validated identfier of the product
// Search for the product
$product = product::read(
filter: "d.identifier == @identifier && d.deleted != true && d.hidden != true",
sort: 'd.created DESC',
amount: 1,
parameters: ['identifier' => $identifier],
errors: $this->errors['cart']
);
if ($product instanceof product) {
// Initialized the product
// Initializing the cart
$this->cart ??= $this->account?->cart() ?? $this->session?->cart();
if ($this->cart instanceof model) {
// Initialized the cart
// Initializing buffer with amount of the product in the cart
$cart = $this->cart->count(product: $product, limit: 100, errors: $this->errors['cart']) ?? 0;
if ($this->cart instanceof model) {
// Initialized the cart
// Validating @todo add throwing errors
if (isset($type) && preg_match('/[\w]+/', urldecode($type), $matches)) $type = $matches[0];
else unset($type);
if (isset($type)) {
// Received and validated type of action with the product
if ($type === 'toggle') {
// Write the product to the cart if is not in the cart and vice versa
if ($cart > 0) {
// The cart has the product
// Deleting the product from the cart
$this->cart->delete(product: $product, amount: $cart, errors: $this->errors['cart']);
// Reinitializing the buffer with amount of the product in the cart
$cart = 0;
} else {
// The cart has no the product
// Writing the product to the cart
$this->cart->write(product: $product, amount: 1, errors: $this->errors['cart']);
// Reinitializing the buffer with amount of the product in the cart
$cart = 1;
}
} else {
// Received not the "toggle" command
// Validating @todo add throwing errors
if (isset($amount) && preg_match('/[\d]+/', urldecode($amount), $matches)) $amount = (int) $matches[0];
else unset($amount);
if (isset($amount)) {
// Received and validated amount parameter for action with the product
if ($type === 'write') {
// Increase amount of the product in the cart
if ($cart + $amount < 101) {
// Validated amount to wrting
// Writing the product to the cart
$this->cart->write(product: $product, amount: $amount, errors: $this->errors['cart']);
// Reinitialize the buffer with amount of the product in the cart
$cart += $amount;
}
} else if ($type === 'delete') {
// Decrease amount of the product in the cart
if ($cart - $amount > -1) {
// Validated amount to deleting
// Deleting the product from the cart
$this->cart->delete(product: $product, amount: $amount, errors: $this->errors['cart']);
// Reinitialize the buffer with amount of the product in the cart
$cart -= $amount;
}
} else if ($type === 'set') {
// Set amount of the product in the cart
if ($amount > -1 && $amount < 101) {
// Validated amount to setting
if ($amount > $cart) {
// Requested amount more than actual amount of the product in the cart
// Writing the product to the cart
$this->cart->write(product: $product, amount: $amount - $cart, errors: $this->errors['cart']);
} else {
// Requested amount less than actual amount of the product in the cart
// Deleting the product from the cart
$this->cart->delete(product: $product, amount: $cart - $amount, errors: $this->errors['cart']);
}
// Reinitializing the buffer with amount of the product in the cart
$cart = $amount;
}
}
}
}
}
}
}
}
}
// Sending response
$this->response
->start()
->clean()
->sse()
->json([
'amount' => $cart, // $cart does not store a real value, but is calculated without a repeated request to ArangoDB
'errors' => $this->errors
])
->validate($this->request)
?->body()
->end();
// Deinitializing buffer with amount of the product in the cart
unset($cart);
}
// Exit (success/fail)
return null;
}
/**
* Summary
*
* Information about products in the cart
*
* @return null
*/
public function summary(): null
{
if (str_contains($this->request->headers['accept'], content::json->value)) {
// Request for JSON response
// Initializing the cart
$this->cart ??= $this->account?->cart() ?? $this->session?->cart();
if ($this->cart instanceof model) {
// Initialized the cart
// Initializing summary data of the cart
$summary = $this->cart?->summary(currency: $this->currency, errors: $this->errors['cart']);
// Sending response
$this->response
->start()
->clean()
->sse()
->json([
'cost' => $summary['cost'] ?? 0,
'amount' => $summary['amount'] ?? 0,
'errors' => $this->errors
])
->validate($this->request)
?->body()
->end();
// Deinitializing summary data of the cart
unset($summary);
}
}
// Exit (success/fail)
return null;
}
/**
* Share
*
* Share the cart
*
* @return null
*/
public function share(): null
{
if (str_contains($this->request->headers['accept'], content::json->value)) {
// Request for JSON response
// Initializing the cart
$this->cart ??= $this->account?->cart() ?? $this->session?->cart();
if ($this->cart instanceof model) {
// Initialized the cart
if ($share = $this->cart->share ?? $this->cart->share()) {
// The cart is available for sharing
// Sending response
$this->response
->start()
->clean()
->sse()
->json([
'share' => $share,
'errors' => $this->errors
])
->validate($this->request)
?->body()
->end();
}
// Deinitializing unnecessary variables
unset($hash);
}
}
// Exit (success/fail)
return null;
}
/**
* Pay
*
* Pay for the cart
*
* @return null
*/
public function pay(): null
{
if (str_contains($this->request->headers['accept'], content::json->value)) {
// Request for JSON response
// Initializing the cart
$this->cart ??= $this->account?->cart() ?? $this->session?->cart();
if ($this->cart instanceof model) {
// Initialized the cart
if ($share = $this->cart->share ?? $this->cart->share()) {
// The cart is available for sharing
// Sending response
$this->response
->start()
->clean()
->sse()
->json([
'share' => $share,
'errors' => $this->errors
])
->validate($this->request)
?->body()
->end();
}
// Deinitializing unnecessary variables
unset($hash);
}
}
// Exit (success/fail)
return null;
}
/**
* Robokassa
*
* HTML-document with robokassa iframe
*
* @param null
*
* @todo THIS MUST BE A PAYMENT OF ORDER IN THE FUTURE, NOT CART
*/
public function robokassa(): null
{
// Initializing the cart
$this->cart ??= $this->account?->cart() ?? $this->session?->cart();
// Initializing the cart data
$this->view->cart = $this->cart;
$this->view->summary = $this->cart?->summary(currency: $this->currency);
if (str_contains($this->request->headers['accept'], content::any->value)) {
// Request for any response
// Render page
$page = $this->view->render('iframes/robokassa.html');
// Sending response
$this->response
->start()
->clean()
->sse()
->write($page)
->validate($this->request)
?->body()
->end();
// Deinitializing rendered page
unset($page);
}
// Exit (success/fail)
return null;
}
}