languages + close button + import fix + total rebuild
This commit is contained in:
parent
8de9a0b158
commit
5fa4abba5f
|
@ -35,11 +35,15 @@ final class catalog extends core
|
|||
*/
|
||||
public function index(array $parameters = []): ?string
|
||||
{
|
||||
if (!empty($parameters['category'])) {
|
||||
// Initializing identifier of a category
|
||||
preg_match('/[\d]+/', $parameters['identifier'] ?? '', $matches);
|
||||
$identifier = $matches[0] ?? null;
|
||||
|
||||
if (!empty($parameters['identifier'])) {
|
||||
// Передана категория (идентификатор)
|
||||
|
||||
// Инициализация актуальной категории
|
||||
$category = new category(document: category::_read('d.identifier == @identifier', parameters: ['identifier' => $parameters['category']]));
|
||||
$category = category::_read('d.identifier == @identifier', parameters: ['identifier' => (int) $identifier], errors: $this->errors['catalog']);
|
||||
|
||||
if ($category instanceof category) {
|
||||
// Found the category
|
||||
|
@ -84,7 +88,10 @@ final class catalog extends core
|
|||
|
||||
// Generating filters
|
||||
$this->view->filters = [
|
||||
'brands' => product::collect('d.brand.ru', $this->errors['catalog'])
|
||||
'brands' => product::collect(
|
||||
'd.brand.' . $this->language->name,
|
||||
errors: $this->errors['catalog']
|
||||
)
|
||||
];
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
|
@ -110,7 +117,7 @@ final class catalog extends core
|
|||
'html' => [
|
||||
'categories' => $this->view->render('catalog/elements/categories.html'),
|
||||
'products' => $this->view->render('catalog/elements/products/2columns.html'),
|
||||
'filters' => $this->view->render('catalog/elemments/filters.html')
|
||||
'filters' => $this->view->render('catalog/elements/filters.html')
|
||||
],
|
||||
'errors' => $this->errors
|
||||
]
|
||||
|
@ -151,6 +158,7 @@ final class catalog extends core
|
|||
filter: 'd.deleted != true && d.hidden != true',
|
||||
sort: 'd.position ASC, d.name ASC, d.created DESC',
|
||||
amount: 30,
|
||||
language: $this->language,
|
||||
errors: $this->errors['catalog']
|
||||
) : [];
|
||||
|
||||
|
@ -167,7 +175,7 @@ final class catalog extends core
|
|||
[
|
||||
'title' => $title ?? '',
|
||||
'html' => [
|
||||
'products' => $this->view->render('catalog/elements/products.html')
|
||||
'products' => $this->view->render('catalog/elements/products/2columns.html')
|
||||
],
|
||||
'errors' => $this->errors
|
||||
]
|
||||
|
@ -195,53 +203,27 @@ final class catalog extends core
|
|||
*/
|
||||
public function product(array $parameters = []): ?string
|
||||
{
|
||||
// Initializing of text fore search
|
||||
preg_match('/[\d]+/', $parameters['id'] ?? '', $matches);
|
||||
$_key = $matches[0] ?? null;
|
||||
// Initializing identifier of a product
|
||||
preg_match('/[\d]+/', $parameters['identifier'] ?? '', $matches);
|
||||
$identifier = $matches[0] ?? null;
|
||||
|
||||
if (!empty($_key)) {
|
||||
// Received id of prouct (_key)
|
||||
if (!empty($identifier)) {
|
||||
// Received identifier of the product
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// POST request
|
||||
|
||||
// Search for products
|
||||
$product = product::read(
|
||||
filter: "d._key == \"$_key\" && d.deleted != true && d.hidden != true",
|
||||
filter: "d.identifier == @identifier && d.deleted != true && d.hidden != true",
|
||||
sort: 'd.created DESC',
|
||||
amount: 1,
|
||||
return: '{id: d._key, title: d.title.ru, description: d.description.ru, cost: d.cost, weight: d.weight, dimensions: d.dimensions, brand: d.brand.ru, compatibility: d.compatibility.ru}',
|
||||
return: '{identifier: d.identifier, name: d.name.@language, description: d.description.@language, cost: d.cost, weight: d.weight, dimensions: d.dimensions, brand: d.brand.@language, compatibility: d.compatibility.@language, images: d.images[*].storage}',
|
||||
parameters: ['identifier' => (int) $identifier],
|
||||
language: $this->language,
|
||||
errors: $this->errors['catalog']
|
||||
)[0]?->getAll();
|
||||
|
||||
if (!empty($product)) {
|
||||
// Found the product
|
||||
|
||||
// Initializing buffer of images
|
||||
$images = [];
|
||||
|
||||
foreach (
|
||||
glob(INDEX .
|
||||
DIRECTORY_SEPARATOR .
|
||||
'themes' .
|
||||
DIRECTORY_SEPARATOR .
|
||||
(THEME ?? 'default') .
|
||||
DIRECTORY_SEPARATOR .
|
||||
'images' .
|
||||
DIRECTORY_SEPARATOR .
|
||||
$_key .
|
||||
DIRECTORY_SEPARATOR .
|
||||
"*.{jpg,png,gif}", GLOB_BRACE) as $file
|
||||
) {
|
||||
// Iterate over images of the product
|
||||
|
||||
// Write to buffer of images
|
||||
$images[] = "/images/$_key/" . basename($file);
|
||||
}
|
||||
|
||||
$product = $product + ['images' => $images];
|
||||
}
|
||||
|
||||
// Initializing a response headers
|
||||
header('Content-Type: application/json');
|
||||
header('Content-Encoding: none');
|
||||
|
|
|
@ -10,7 +10,8 @@ use mirzaev\arming_bot\views\templater,
|
|||
mirzaev\arming_bot\models\account,
|
||||
mirzaev\arming_bot\models\session,
|
||||
mirzaev\arming_bot\models\settings,
|
||||
mirzaev\arming_bot\models\suspension;
|
||||
mirzaev\arming_bot\models\suspension,
|
||||
mirzaev\arming_bot\models\enumerations\language;
|
||||
|
||||
// Framework for PHP
|
||||
use mirzaev\minimal\controller;
|
||||
|
@ -31,7 +32,7 @@ class core extends controller
|
|||
/**
|
||||
* Instance of the settings
|
||||
*/
|
||||
public static settings $settings;
|
||||
protected readonly settings $settings;
|
||||
|
||||
/**
|
||||
* Instance of a session
|
||||
|
@ -43,6 +44,11 @@ class core extends controller
|
|||
*/
|
||||
protected readonly ?account $account;
|
||||
|
||||
/**
|
||||
* Language
|
||||
*/
|
||||
protected language $language = language::en;
|
||||
|
||||
/**
|
||||
* Registry of errors
|
||||
*/
|
||||
|
@ -57,6 +63,8 @@ class core extends controller
|
|||
* @param bool $initialize Initialize a controller?
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @todo settings account и session не имеют проверок на возврат null
|
||||
*/
|
||||
public function __construct(bool $initialize = true)
|
||||
{
|
||||
|
@ -70,7 +78,7 @@ class core extends controller
|
|||
// Initializing is requested
|
||||
|
||||
// Initializing of models core (connect to ArangoDB...)
|
||||
new models();
|
||||
new models(true);
|
||||
|
||||
// Initializing of the date until which the session will be active
|
||||
$expires = strtotime('+1 week');
|
||||
|
@ -106,10 +114,18 @@ class core extends controller
|
|||
$this->account = $this->session->account($this->errors['account']);
|
||||
|
||||
// Initializing of the settings
|
||||
self::$settings = settings::active();
|
||||
$this->settings = settings::active();
|
||||
|
||||
// Initializing of language
|
||||
if ($this->account?->language) $this->language = $this->account->language ?? language::en;
|
||||
else if ($this->settings?->language) $this->language = $this->settings->language ?? language::en;
|
||||
|
||||
// Initializing of preprocessor of views
|
||||
$this->view = new templater($this->session, $this->account);
|
||||
$this->view = new templater(
|
||||
session: $this->session,
|
||||
account: $this->account,
|
||||
settings: $this->settings
|
||||
);
|
||||
|
||||
// @todo перенести в middleware
|
||||
|
||||
|
@ -142,20 +158,20 @@ class core extends controller
|
|||
suspension:
|
||||
|
||||
// Write title of the page to templater global variables
|
||||
$this->view->title = match ($account?->language ?? self::$settings?->language) {
|
||||
'ru' => 'Приостановлено',
|
||||
'en' => 'Suspended',
|
||||
$this->view->title = match ($this->language) {
|
||||
language::en => 'Suspended',
|
||||
language::ru => 'Приостановлено',
|
||||
default => 'Suspended'
|
||||
};
|
||||
|
||||
// Write description of the suspension to templater global variables
|
||||
$this->view->description = $suspension->description[$account?->language ?? self::$settings?->language] ?? array_values($suspension->description)[0];
|
||||
$this->view->description = $suspension->description[$this->language] ?? array_values($suspension->description)[0];
|
||||
|
||||
// Write message of remaining time of the suspension to templater global variables
|
||||
$this->view->remain = [
|
||||
'title' => match ($account?->language ?? self::$settings?->language) {
|
||||
'ru' => 'Осталось времени: ',
|
||||
'en' => 'Time remaining: ',
|
||||
'title' => match ($this->language) {
|
||||
language::en => 'Time remaining: ',
|
||||
language::ru => 'Осталось времени: ',
|
||||
default => 'Time remaining: '
|
||||
},
|
||||
'value' => $suspension?->message()
|
||||
|
|
|
@ -8,7 +8,8 @@ namespace mirzaev\arming_bot\models;
|
|||
use mirzaev\arming_bot\models\core,
|
||||
mirzaev\arming_bot\models\traits\status,
|
||||
mirzaev\arming_bot\models\traits\document as arangodb_document_trait,
|
||||
mirzaev\arming_bot\models\interfaces\document as arangodb_document_interface;
|
||||
mirzaev\arming_bot\models\interfaces\document as arangodb_document_interface,
|
||||
mirzaev\arming_bot\models\enumerations\language;
|
||||
|
||||
// Framework for ArangoDB
|
||||
use mirzaev\arangodb\collection,
|
||||
|
@ -17,6 +18,9 @@ use mirzaev\arangodb\collection,
|
|||
// Framework for Telegram
|
||||
use Zanzara\Telegram\Type\User as telegram;
|
||||
|
||||
// Library for ArangoDB
|
||||
use ArangoDBClient\Document as _document;
|
||||
|
||||
// Built-in libraries
|
||||
use exception;
|
||||
|
||||
|
@ -52,73 +56,87 @@ final class account extends core implements arangodb_document_interface
|
|||
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||
// Initialized the collection
|
||||
|
||||
try {
|
||||
// Initializing the account and exit (success)
|
||||
return new static(
|
||||
document: collection::execute(
|
||||
<<<'AQL'
|
||||
FOR d IN @@collection
|
||||
FILTER d.identifier == @identifier
|
||||
RETURN d
|
||||
AQL,
|
||||
// Initializing the account
|
||||
$result = collection::execute(
|
||||
<<<'AQL'
|
||||
FOR d IN @@collection
|
||||
FILTER d.identifier == @identifier
|
||||
RETURN d
|
||||
AQL,
|
||||
[
|
||||
'@collection' => static::COLLECTION,
|
||||
'identifier' => $identifier
|
||||
],
|
||||
errors: $errors
|
||||
);
|
||||
|
||||
if ($result instanceof _document) {
|
||||
// Initialized the account
|
||||
|
||||
// Initializing the object
|
||||
$account = new account;
|
||||
|
||||
if (method_exists($account, '__document')) {
|
||||
// Object can implement a document from ArangoDB
|
||||
|
||||
// Abstractioning of parameters
|
||||
$result->language = language::{$result->language} ?? 'en';
|
||||
|
||||
// Writing the instance of account document from ArangoDB to the implement object
|
||||
$account->__document($result);
|
||||
|
||||
// Exit (success)
|
||||
return $account;
|
||||
}
|
||||
} else if ($registration) {
|
||||
// Not found the account and registration is requested
|
||||
|
||||
// Creating account
|
||||
$_id = document::write(
|
||||
static::COLLECTION,
|
||||
(is_array($registration)
|
||||
? $registration :
|
||||
[
|
||||
'@collection' => static::COLLECTION,
|
||||
'identifier' => $identifier
|
||||
],
|
||||
errors: $errors
|
||||
)
|
||||
'identifier' => $registration->getId(),
|
||||
'name' => [
|
||||
'first' => $registration->getFirstName(),
|
||||
'last' => $registration->getLastName()
|
||||
],
|
||||
'domain' => $registration->getUsername(),
|
||||
'robot' => $registration->isBot(),
|
||||
'banned' => false,
|
||||
'tester' => false,
|
||||
'developer' => false,
|
||||
'access' => [
|
||||
'settings' => false
|
||||
],
|
||||
'menus' => [
|
||||
'attachments' => $registration->getAddedToAttachmentMenu()
|
||||
],
|
||||
'messages' => true,
|
||||
'groups' => [
|
||||
'join' => $registration->getCanJoinGroups(),
|
||||
'messages' => $registration->getCanReadAllGroupMessages()
|
||||
],
|
||||
'premium' => $registration->isPremium(),
|
||||
'language' => language::{$registration->getLanguageCode()}->name ?? 'en',
|
||||
'queries' => [
|
||||
'inline' => $registration->getSupportsInlineQueries()
|
||||
]
|
||||
]) + [
|
||||
'version' => ROBOT_VERSION,
|
||||
'active' => true
|
||||
],
|
||||
errors: $errors
|
||||
);
|
||||
} catch (exception $e) {
|
||||
if ($registration) {
|
||||
// Not found the account and registration is requested
|
||||
|
||||
// Creating account
|
||||
$account = document::write(
|
||||
static::COLLECTION,
|
||||
(is_array($registration)
|
||||
? $registration :
|
||||
[
|
||||
'identifier' => $registration->getId(),
|
||||
'name' => [
|
||||
'first' => $registration->getFirstName(),
|
||||
'last' => $registration->getLastName()
|
||||
],
|
||||
'domain' => $registration->getUsername(),
|
||||
'robot' => $registration->isBot(),
|
||||
'banned' => false,
|
||||
'tester' => false,
|
||||
'developer' => false,
|
||||
'access' => [
|
||||
'settings' => false
|
||||
],
|
||||
'menus' => [
|
||||
'attachments' => $registration->getAddedToAttachmentMenu()
|
||||
],
|
||||
'messages' => true,
|
||||
'groups' => [
|
||||
'join' => $registration->getCanJoinGroups(),
|
||||
'messages' => $registration->getCanReadAllGroupMessages()
|
||||
],
|
||||
'premium' => $registration->isPremium(),
|
||||
'language' => $registration->getLanguageCode(),
|
||||
'queries' => [
|
||||
'inline' => $registration->getSupportsInlineQueries()
|
||||
]
|
||||
]) + [
|
||||
'version' => ROBOT_VERSION,
|
||||
'active' => true
|
||||
],
|
||||
errors: $errors
|
||||
);
|
||||
if ($_id) {
|
||||
// Created account
|
||||
|
||||
if ($account) {
|
||||
// Created account
|
||||
|
||||
// Initializing of the account (without registration request)
|
||||
return static::initialize($identifier, errors: $errors);
|
||||
} else throw new exception('Failed to register account');
|
||||
} else throw new exception('Failed to find account');
|
||||
}
|
||||
// Initializing of the account (without registration request)
|
||||
return static::initialize($identifier, errors: $errors);
|
||||
} else throw new exception('Failed to register account');
|
||||
} else throw new exception('Failed to find account');
|
||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||
} catch (exception $e) {
|
||||
// Writing to the registry of errors
|
||||
|
|
|
@ -10,6 +10,7 @@ use mirzaev\arming_bot\models\core,
|
|||
mirzaev\arming_bot\models\category,
|
||||
mirzaev\arming_bot\models\entry,
|
||||
mirzaev\arming_bot\models\traits\files,
|
||||
mirzaev\arming_bot\models\enumerations\language,
|
||||
mirzaev\arming_bot\models\traits\yandex\disk as yandex;
|
||||
|
||||
// Framework for ArangoDB
|
||||
|
@ -40,26 +41,26 @@ final class catalog extends core
|
|||
* Collect parameter from all products
|
||||
*
|
||||
* @param string $documment Path to the EXCEL-document
|
||||
* @param int &$categories_loaded Counter of loaded categories
|
||||
* @param int &$categories_created Counter of created categories
|
||||
* @param int &$categories_updated Counter of updated categories
|
||||
* @param int &$categories_deleted Counter of deleted categories
|
||||
* @param int &$categories_new Counter of new categories
|
||||
* @param int &$categories_old Counter of old categories
|
||||
* @param int &$products_loaded Counter of loaded products
|
||||
* @param int &$products_created Counter of created products
|
||||
* @param int &$products_updated Counter of updated products
|
||||
* @param int &$products_deleted Counter of deleted products
|
||||
* @param int &$products_new Counter of new products
|
||||
* @param int &$products_old Counter of old products
|
||||
* @param string &$language Language (en, ru...)
|
||||
* @param int &$categories_loaded Counter of loaded categories
|
||||
* @param int &$categories_created Counter of created categories
|
||||
* @param int &$categories_updated Counter of updated categories
|
||||
* @param int &$categories_deleted Counter of deleted categories
|
||||
* @param int &$categories_new Counter of new categories
|
||||
* @param int &$categories_old Counter of old categories
|
||||
* @param int &$products_loaded Counter of loaded products
|
||||
* @param int &$products_created Counter of created products
|
||||
* @param int &$products_updated Counter of updated products
|
||||
* @param int &$products_deleted Counter of deleted products
|
||||
* @param int &$products_new Counter of new products
|
||||
* @param int &$products_old Counter of old products
|
||||
* @param language $language Language
|
||||
* @param array &$errors Registry of errors
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @todo
|
||||
* 1. Сначала создать все категории и затем снова по циклу пройтись уже создавать entry между ними
|
||||
* 2. Сжимать изображения
|
||||
* 2. Сжимать изображения
|
||||
*/
|
||||
public static function import(
|
||||
string $document,
|
||||
|
@ -75,7 +76,7 @@ final class catalog extends core
|
|||
int &$products_deleted = 0,
|
||||
int &$products_old = 0,
|
||||
int &$products_new = 0,
|
||||
string $language = 'en',
|
||||
language $language = language::en,
|
||||
array &$errors = []
|
||||
): void {
|
||||
try {
|
||||
|
@ -112,7 +113,7 @@ final class catalog extends core
|
|||
|
||||
try {
|
||||
if (!empty($row['identifier']) && !empty($row['name'])) {
|
||||
// All required cells are filled in
|
||||
// Required cells are filled in
|
||||
|
||||
// Incrementing the counter of loaded categories
|
||||
++$categories_loaded;
|
||||
|
@ -123,36 +124,40 @@ final class catalog extends core
|
|||
// Declaring the variable with the category
|
||||
$category = null;
|
||||
|
||||
try {
|
||||
// Initializing the category
|
||||
$category = new category(document: category::_read('d.identifier == @identifier', parameters: ['identifier' => (int) $row['identifier']], errors: $errors)[0] ?? null);
|
||||
// Initializing the category
|
||||
$category = category::_read('d.identifier == @identifier', parameters: ['identifier' => (int) $row['identifier']], errors: $errors);
|
||||
|
||||
if ($category instanceof category) {
|
||||
// Initialized the category
|
||||
|
||||
// Initializing name of the category
|
||||
$category->name[$language] === $row['name'] || $category->name = [[$language => $row['name']]] + $category->name ?? [];
|
||||
if (empty($category->name) || empty($category->name[$language->name]) || $category->name[$language->name] !== $row['name'])
|
||||
$category->name = [$language->name => $row['name']] + ($category->name ?? []);
|
||||
|
||||
// Initializing position of the category
|
||||
$category->position === $row['position'] || $category->position = $row['position'];
|
||||
} catch (exception $e) {
|
||||
// Not found the category
|
||||
if (empty($category->position) || $category->position === $row['position'])
|
||||
$category->position = $row['position'];
|
||||
} else {
|
||||
// Not initialized the category
|
||||
|
||||
// Creating the category
|
||||
$_id = category::write((int) $row['identifier'], [$language => $row['name']], $row['position'] ?? null, $errors);
|
||||
$_id = $created = category::write((int) $row['identifier'], [$language->name => $row['name']], $row['position'] ?? null, $errors);
|
||||
|
||||
// Initializing the category
|
||||
$category = new category(document: $created = category::_read('d._id == @_id', parameters: ['_id' => $_id], errors: $errors)[0] ?? null);
|
||||
$category = category::_read('d._id == @_id', parameters: ['_id' => $_id], errors: $errors);
|
||||
|
||||
// Incrementing the counter of created categories
|
||||
if ($created) ++$categories_created;
|
||||
};
|
||||
|
||||
if ($category instanceof category) {
|
||||
// Found the category
|
||||
// Initialized the category
|
||||
|
||||
if (!empty($row['category'])) {
|
||||
// Received the ascendant category
|
||||
|
||||
// Initializing the ascendant category
|
||||
$ascendant = new category(document: category::_read('d.identifier == @identifier', parameters: ['identifier' => (int) $row['category']], errors: $errors)[0] ?? null);
|
||||
$ascendant = category::_read('d.identifier == @identifier', parameters: ['identifier' => (int) $row['category']], errors: $errors);
|
||||
|
||||
if ($ascendant instanceof category) {
|
||||
// Found the ascendant category
|
||||
|
@ -265,7 +270,7 @@ final class catalog extends core
|
|||
|
||||
try {
|
||||
if (!empty($row['identifier']) && !empty($row['name'])) {
|
||||
// All required cells are filled in
|
||||
// Required cells are filled in
|
||||
|
||||
// Incrementing the counter of loaded products
|
||||
++$products_loaded;
|
||||
|
@ -276,45 +281,63 @@ final class catalog extends core
|
|||
// Declaring the variable with the product
|
||||
$product = null;
|
||||
|
||||
try {
|
||||
// Initializing the product
|
||||
$product = new product(document: product::_read('d.identifier == %u', parameters: ['identifier' => (int) $row['identifier']], errors: $errors)[0] ?? null);
|
||||
// Initializing the product
|
||||
$product = product::_read('d.identifier == @identifier', parameters: ['identifier' => (int) $row['identifier']], errors: $errors);
|
||||
|
||||
// Initializing name of the category
|
||||
$product->name[$language] === $row['name'] || $product->name = [[$language => $row['name']]] + $product->name ?? [];
|
||||
if ($product instanceof product) {
|
||||
// Initialized the product
|
||||
|
||||
// Initializing name of the product
|
||||
if (empty($product->name) || empty($product->name[$language->name]) || $product->name[$language->name] !== $row['name'])
|
||||
$product->name = [$language->name => $row['name']] + ($product->name ?? []);
|
||||
|
||||
// Initializing description of the product
|
||||
if (empty($product->description) || empty($product->description[$language->name]) || $product->description[$language->name] !== $row['description'])
|
||||
$product->description = [$language->name => $row['description']] + ($product->description ?? []);
|
||||
|
||||
// Initializing brand of the product
|
||||
if (empty($product->brand) || empty($product->brand[$language->name]) || $product->brand[$language->name] !== $row['brand'])
|
||||
$product->brand = [$language->name => $row['brand']] + ($product->brand ?? []);
|
||||
|
||||
// Initializing compatibility of the product
|
||||
if (empty($product->compatibility) || empty($product->brand[$language->name]) || $product->compatibility[$language->name] !== $row['compatibility'])
|
||||
$product->compatibility = [$language->name => $row['compatibility']] + ($product->compatibility ?? []);
|
||||
|
||||
// Initializing position of the product
|
||||
$product->position === $row['position'] || $product->position = $row['position'];
|
||||
} catch (exception $e) {
|
||||
// Not found the product
|
||||
if (empty($product->position) || $product->position !== $row['position'])
|
||||
$product->position = $row['position'];
|
||||
} else {
|
||||
// Not initialized the product
|
||||
|
||||
// Creating the product
|
||||
$_id = product::write(
|
||||
(int) $row['identifier'],
|
||||
[$language => $row['name']],
|
||||
[$language => $row['description']],
|
||||
[$language->name => $row['name']],
|
||||
[$language->name => $row['description']],
|
||||
(float) $row['cost'],
|
||||
(float) $row['weight'],
|
||||
['x' => $row['x'], 'y' => $row['y'], 'z' => $row['z']],
|
||||
[$language->name => $row['brand']],
|
||||
[$language->name => $row['compatibility']],
|
||||
$row['position'] ?? null,
|
||||
errors: $errors
|
||||
);
|
||||
|
||||
// Initializing the product
|
||||
$product = new product(document: $created = product::_read(sprintf('d._id == "%s"', $_id), errors: $errors)[0] ?? null);
|
||||
$product = $created = product::_read('d._id == @_id', parameters: ['_id' => $_id], errors: $errors);
|
||||
|
||||
// Incrementing the counter of created products
|
||||
if ($created) ++$products_created;
|
||||
}
|
||||
|
||||
if ($product instanceof product) {
|
||||
// Found the product
|
||||
// Initialized the product
|
||||
|
||||
if (!empty($row['category'])) {
|
||||
// Received the category
|
||||
|
||||
// Initializing the category
|
||||
$category = new category(document: category::_read(sprintf('d.identifier == %u', (int) $row['category']), errors: $errors)[0] ?? null);
|
||||
$category = category::_read(sprintf('d.identifier == %u', (int) $row['category']), errors: $errors);
|
||||
|
||||
if ($category instanceof category) {
|
||||
// Found the ascendant category
|
||||
|
@ -410,7 +433,7 @@ final class catalog extends core
|
|||
sort: 'd.updated DESC',
|
||||
amount: 100000,
|
||||
errors: $errors
|
||||
) as $document
|
||||
) ?? [] as $document
|
||||
) {
|
||||
// Iterating over categories
|
||||
|
||||
|
@ -444,7 +467,7 @@ final class catalog extends core
|
|||
sort: 'd.updated DESC',
|
||||
amount: 100000,
|
||||
errors: $errors
|
||||
) as $document
|
||||
) ?? [] as $document
|
||||
) {
|
||||
// Iterating over products
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ use mirzaev\arangodb\connection as arangodb,
|
|||
mirzaev\arangodb\collection,
|
||||
mirzaev\arangodb\enumerations\collection\type;
|
||||
|
||||
// Libraries for ArangoDB
|
||||
// Library for ArangoDB
|
||||
use ArangoDBClient\Document as _document;
|
||||
|
||||
// Built-in libraries
|
||||
|
@ -40,6 +40,8 @@ class core extends model
|
|||
|
||||
/**
|
||||
* Instance of the session of ArangoDB
|
||||
*
|
||||
* @todo ПЕРЕДЕЛАТЬ В php 8.4
|
||||
*/
|
||||
protected static arangodb $arangodb;
|
||||
|
||||
|
@ -61,7 +63,7 @@ class core extends model
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(bool $initialize = true, ?arangodb $arangodb = null)
|
||||
public function __construct(bool $initialize = false, ?arangodb $arangodb = null)
|
||||
{
|
||||
// For the extends system
|
||||
parent::__construct($initialize);
|
||||
|
@ -69,17 +71,8 @@ class core extends model
|
|||
if ($initialize) {
|
||||
// Initializing is requested
|
||||
|
||||
if (isset($arangodb)) {
|
||||
// Recieved an instance of a session of ArangoDB
|
||||
|
||||
// Writing an instance of a session of ArangoDB to the property
|
||||
$this->__set('arangodb', $arangodb);
|
||||
} else {
|
||||
// Not recieved an instance of a session of ArangoDB
|
||||
|
||||
// Initializing of an instance of a session of ArangoDB
|
||||
$this->__get('arangodb');
|
||||
}
|
||||
// Writing an instance of a session of ArangoDB to the property
|
||||
self::$arangodb = $arangodb ?? new arangodb(require static::ARANGODB);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +97,7 @@ class core extends model
|
|||
string $return = 'd',
|
||||
array $parameters = [],
|
||||
array &$errors = []
|
||||
): _document|array|null {
|
||||
): _document|static|array|null {
|
||||
try {
|
||||
if (collection::initialize(static::COLLECTION, static::TYPE)) {
|
||||
// Initialized the collection
|
||||
|
@ -117,22 +110,39 @@ class core extends model
|
|||
%s
|
||||
%s
|
||||
LIMIT @offset, @amount
|
||||
RETURN @return
|
||||
RETURN %s
|
||||
AQL,
|
||||
empty($filter) ? '' : "FILTER $filter",
|
||||
empty($sort) ? '' : "SORT $sort",
|
||||
empty($return) ? 'd' : $return
|
||||
),
|
||||
[
|
||||
'@collection' => static::COLLECTION,
|
||||
'offset' => --$page <= 0 ? 0 : $page * $amount,
|
||||
'amount' => $amount,
|
||||
'return' => $return
|
||||
'amount' => $amount
|
||||
] + $parameters,
|
||||
errors: $errors
|
||||
errors: $errors
|
||||
);
|
||||
|
||||
if ($result instanceof _document) {
|
||||
// Received only 1 document and
|
||||
|
||||
// Initializing the object
|
||||
$object = new static;
|
||||
|
||||
if (method_exists($object, '__document')) {
|
||||
// Object can implement a document from ArangoDB
|
||||
|
||||
// Writing the instance of document from ArangoDB to the implement object
|
||||
$object->__document($result);
|
||||
|
||||
// Exit (success)
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
// Exit (success)
|
||||
return is_array($result) ? $result : [$result];
|
||||
return $result;
|
||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||
} catch (exception $e) {
|
||||
// Writing to registry of errors
|
||||
|
@ -160,26 +170,9 @@ class core extends model
|
|||
{
|
||||
match ($name) {
|
||||
'arangodb' => (function () use ($value) {
|
||||
if ($this->__isset('arangodb')) {
|
||||
// Is alredy initialized
|
||||
|
||||
// Exit (fail)
|
||||
throw new exception('Forbidden to reinitialize the session of ArangoDB ($this::$arangodb)', 500);
|
||||
} else {
|
||||
// Is not already initialized
|
||||
|
||||
if ($value instanceof arangodb) {
|
||||
// Recieved an appropriate value
|
||||
|
||||
// Writing the property and exit (success)
|
||||
self::$arangodb = $value;
|
||||
} else {
|
||||
// Recieved an inappropriate value
|
||||
|
||||
// Exit (fail)
|
||||
throw new exception('Session of ArangoDB ($this::$arangodb) is need to be mirzaev\arangodb\connection', 500);
|
||||
}
|
||||
}
|
||||
if (isset(static::$arangodb)) throw new exception('Forbidden to reinitialize the session of ArangoDB ($this::$arangodb)', 500);
|
||||
else if ($value instanceof arangodb) self::$arangodb = $value;
|
||||
else throw new exception('Session of connection to ArangoDB ($this::$arangodb) is need to be mirzaev\arangodb\connection', 500);
|
||||
})(),
|
||||
default => parent::__set($name, $value)
|
||||
};
|
||||
|
@ -195,22 +188,6 @@ class core extends model
|
|||
public function __get(string $name): mixed
|
||||
{
|
||||
return match ($name) {
|
||||
'arangodb' => (function () {
|
||||
try {
|
||||
if (!$this->__isset('arangodb')) {
|
||||
// Is not initialized
|
||||
|
||||
// Initializing of a default value from settings
|
||||
$this->__set('arangodb', new arangodb(require static::ARANGODB));
|
||||
}
|
||||
|
||||
// Exit (success)
|
||||
return self::$arangodb;
|
||||
} catch (exception) {
|
||||
// Exit (fail)
|
||||
return null;
|
||||
}
|
||||
})(),
|
||||
default => parent::__get($name)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -227,7 +227,8 @@ final class entry extends core implements arangodb_document_interface
|
|||
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||
// Initialized collections
|
||||
|
||||
if ($documents = collection::execute(
|
||||
// Execute and exit (success)
|
||||
return is_array($result = collection::execute(
|
||||
sprintf(
|
||||
<<<'AQL'
|
||||
FOR v IN 1..1 INBOUND @document GRAPH @graph
|
||||
|
@ -241,18 +242,13 @@ final class entry extends core implements arangodb_document_interface
|
|||
empty($sort) ? '' : "SORT $sort",
|
||||
),
|
||||
[
|
||||
'grapth' => 'catalog',
|
||||
'graph' => 'catalog',
|
||||
'document' => $document->getId(),
|
||||
'offset' => --$page <= 0 ? $page = 0 : $page * $amount,
|
||||
'amount' => $amount
|
||||
],
|
||||
errors: $errors
|
||||
)) {
|
||||
// Fount entries
|
||||
|
||||
// Возврат (успех)
|
||||
return is_array($documents) ? $documents : [$documents];
|
||||
} else return [];
|
||||
)) ? $result : [$result];
|
||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||
} else throw new exception('Failed to initialize ' . $document::TYPE . ' collection: ' . $document::COLLECTION);
|
||||
} catch (exception $e) {
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace mirzaev\arming_bot\models\enumerations;
|
||||
|
||||
/**
|
||||
* Types of human languages
|
||||
*
|
||||
* @package mirzaev\arming_bot\models\enumerations
|
||||
*
|
||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||
*/
|
||||
enum language
|
||||
{
|
||||
case en;
|
||||
case ru;
|
||||
|
||||
/**
|
||||
* Translate label of language
|
||||
*
|
||||
* @param language|null $language Language into which to translate
|
||||
*
|
||||
* @return string Translated label of language
|
||||
*
|
||||
* @todo
|
||||
* 1. More languages
|
||||
* 2. Cases???
|
||||
*/
|
||||
public function translate(?language $language = language::en): string
|
||||
{
|
||||
// Exit (success)
|
||||
return match ($this) {
|
||||
language::en => match ($language) {
|
||||
language::en => 'English',
|
||||
language::ru => 'Английский'
|
||||
},
|
||||
language::ru => match ($language) {
|
||||
language::en => 'Russian',
|
||||
language::ru => 'Русский'
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -4,6 +4,14 @@ declare(strict_types=1);
|
|||
|
||||
namespace mirzaev\arming_bot\models\enumerations;
|
||||
|
||||
/**
|
||||
* Types of session verification
|
||||
*
|
||||
* @package mirzaev\arming_bot\models\enumerations
|
||||
*
|
||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||
*/
|
||||
enum session
|
||||
{
|
||||
case hash_only;
|
||||
|
|
|
@ -7,9 +7,6 @@ namespace mirzaev\arming_bot\models\interfaces;
|
|||
// Library для ArangoDB
|
||||
use ArangoDBClient\Document as _document;
|
||||
|
||||
// Framework for ArangoDB
|
||||
use mirzaev\arangodb\connection as arangodb;
|
||||
|
||||
/**
|
||||
* Interface for implementing a document instance from ArangoDB
|
||||
*
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace mirzaev\arming_bot\models;
|
|||
|
||||
// Files of the project
|
||||
use mirzaev\arming_bot\models\core,
|
||||
mirzaev\arming_bot\models\enumerations\language,
|
||||
mirzaev\arming_bot\models\traits\document as arangodb_document_trait;
|
||||
|
||||
// Framework for ArangoDB
|
||||
|
@ -41,6 +42,8 @@ final class product extends core
|
|||
* @param float $cost Cost
|
||||
* @param float $weight Weight
|
||||
* @param array $dimensions Dimensions ['x' => 0.0, 'y' => 0.0, 'z' => 0.0]
|
||||
* @param array|null $brand Brand [['en' => value], ['ru' => значение]]
|
||||
* @param array|null $compatibility Compatibility [['en' => value], ['ru' => значение]]
|
||||
* @param array $images Images (first will be thumbnail)
|
||||
* @param int|null $position Position for sorting in the catalog (ASC)
|
||||
* @param array $data Data
|
||||
|
@ -58,6 +61,8 @@ final class product extends core
|
|||
float $cost = 0,
|
||||
float $weight = 0,
|
||||
array $dimensions = ['x' => 0, 'y' => 0, 'z' => 0],
|
||||
?array $brand = [['en' => 'ERROR']],
|
||||
?array $compatibility = [['en' => 'ERROR']],
|
||||
array $images = [],
|
||||
?int $position = null,
|
||||
array $data = [],
|
||||
|
@ -81,6 +86,8 @@ final class product extends core
|
|||
'y' => $dimensions['y'] ?? 0,
|
||||
'z' => $dimensions['z'] ?? 0,
|
||||
],
|
||||
'brand' => $brand,
|
||||
'compatibility' => $compatibility,
|
||||
'images' => $images,
|
||||
'position' => $position,
|
||||
'version' => ROBOT_VERSION
|
||||
|
@ -111,7 +118,8 @@ final class product extends core
|
|||
* @param int $page Page
|
||||
* @param int $amount Amount per page
|
||||
* @param string|null $return Return (AQL)
|
||||
* @param string $language Language code (en, ru...)
|
||||
* @param language $language Language code (en, ru...)
|
||||
* @param array $parameters Binded parameters for placeholders ['placeholder' => parameter]
|
||||
* @param array &$errors Registry of errors
|
||||
*
|
||||
* @return array Массив с найденными товарами (может быть пустым)
|
||||
|
@ -123,24 +131,32 @@ final class product extends core
|
|||
int $page = 1,
|
||||
int $amount = 100,
|
||||
?string $return = 'd',
|
||||
string $language = 'en',
|
||||
language $language = language::en,
|
||||
array $parameters = [],
|
||||
array &$errors = []
|
||||
): array {
|
||||
try {
|
||||
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||
// Initialized the collection
|
||||
|
||||
// Initializing the query
|
||||
$aql = <<<'AQL'
|
||||
FOR d IN @@collection
|
||||
AQL;
|
||||
// Initializing parameters for search
|
||||
if ($search) $parameters += [
|
||||
'search' => $search,
|
||||
'analyzer' => 'text_' . $language->name
|
||||
];
|
||||
|
||||
if ($search) {
|
||||
// Requested search
|
||||
|
||||
// Writing to the query
|
||||
$aql .= <<<'AQL'
|
||||
SEARCH
|
||||
// Reading products
|
||||
$documents = collection::execute(
|
||||
sprintf(
|
||||
<<<'AQL'
|
||||
FOR d IN @@collection %s
|
||||
%s
|
||||
%s
|
||||
LIMIT @offset, @amount
|
||||
RETURN %s
|
||||
AQL,
|
||||
empty($search) ? '' : <<<'AQL'
|
||||
SEARCH
|
||||
LEVENSHTEIN_MATCH(
|
||||
d.name.@language,
|
||||
TOKENS(@search, @analyzer)[0],
|
||||
|
@ -158,35 +174,18 @@ final class product extends core
|
|||
tokens(@search, @analyzer)[0],
|
||||
1,
|
||||
false
|
||||
)
|
||||
AQL;
|
||||
|
||||
// Adding sorting
|
||||
if ($sort) $sort = "BM25(d) DESC, $sort";
|
||||
else $sort = "BM25(d) DESC";
|
||||
}
|
||||
|
||||
// Reading products
|
||||
$documents = collection::execute(
|
||||
sprintf(
|
||||
$aql . <<<'AQL'
|
||||
%s
|
||||
%s
|
||||
LIMIT @offset, @amount
|
||||
RETURN $s
|
||||
)
|
||||
AQL,
|
||||
empty($filter) ? '' : "FILTER $filter",
|
||||
empty($sort) ? '' : "SORT $sort",
|
||||
empty($search) ? (empty($sort) ? '' : "SORT $sort") : (empty($sort) ? "SORT BM25(d) DESC" : "SORT BM25(d) DESC, $sort"),
|
||||
empty($return) ? 'd' : $return
|
||||
),
|
||||
[
|
||||
'@collection' => $search ? static::COLLECTION . 's_search' : static::COLLECTION,
|
||||
'search' => $search,
|
||||
'language' => $language,
|
||||
'analyzer' => "text_$language",
|
||||
'@collection' => empty($search) ? static::COLLECTION : static::COLLECTION . 's_search',
|
||||
'language' => $language->name,
|
||||
'offset' => --$page <= 0 ? $page = 0 : $page * $amount,
|
||||
'amount' => $amount,
|
||||
],
|
||||
] + $parameters,
|
||||
errors: $errors
|
||||
);
|
||||
|
||||
|
@ -196,7 +195,7 @@ final class product extends core
|
|||
// Exit (success)
|
||||
return is_array($documents) ? $documents : [$documents];
|
||||
} else return [];
|
||||
} else throw new exception('Failed to initialize ' . static::COLLECTION . ' collection: ' . static::COLLECTION);
|
||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||
} catch (exception $e) {
|
||||
// Writing to the registry of errors
|
||||
$errors[] = [
|
||||
|
@ -227,9 +226,9 @@ final class product extends core
|
|||
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||
// Initialized the collection
|
||||
|
||||
if ($values = collection::execute(
|
||||
if ($result = collection::execute(
|
||||
<<<'AQL'
|
||||
FOR d IN @@collecton
|
||||
FOR d IN @@collection
|
||||
RETURN DISTINCT @parameter
|
||||
AQL,
|
||||
[
|
||||
|
@ -241,7 +240,7 @@ final class product extends core
|
|||
// Found parameters
|
||||
|
||||
// Exit (success)
|
||||
return $values;
|
||||
return is_array($result) ? $result : [$result];
|
||||
} else return [];
|
||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||
} catch (exception $e) {
|
||||
|
|
|
@ -141,7 +141,7 @@ final class session extends core implements arangodb_document_interface
|
|||
// Initialized collections
|
||||
|
||||
// Search for connected account
|
||||
$document = collection::execute(
|
||||
$result = collection::execute(
|
||||
<<<AQL
|
||||
FOR v IN INBOUND @session GRAPH sessions
|
||||
SORT v.created DESC
|
||||
|
@ -154,17 +154,21 @@ final class session extends core implements arangodb_document_interface
|
|||
errors: $errors
|
||||
);
|
||||
|
||||
if ($document instanceof _document) {
|
||||
// Found connected account
|
||||
if ($result instanceof _document) {
|
||||
// Found active settings
|
||||
|
||||
// Initializing the implement object of the instance of sesson document from ArangoDB
|
||||
$account = new account;
|
||||
// Initializing the object
|
||||
$account = new static;
|
||||
|
||||
// Writing the instance of session document from ArangoDB to the implement object
|
||||
$account->__document($document);
|
||||
if (method_exists($account, '__document')) {
|
||||
// Object can implement a document from ArangoDB
|
||||
|
||||
// Exit (success)
|
||||
return $account;
|
||||
// Writing the instance of account document from ArangoDB to the implement object
|
||||
$account->__document($result);
|
||||
|
||||
// Exit (success)
|
||||
return $account;
|
||||
}
|
||||
} else return null;
|
||||
} else throw new exception('Failed to initialize ' . account::TYPE . ' collection: ' . account::COLLECTION);
|
||||
} else throw new exception('Failed to initialize ' . connect::TYPE . ' collection: ' . connect::COLLECTION);
|
||||
|
|
|
@ -7,7 +7,8 @@ namespace mirzaev\arming_bot\models;
|
|||
// Files of the project
|
||||
use mirzaev\arming_bot\models\core,
|
||||
mirzaev\arming_bot\models\traits\document as arangodb_document_trait,
|
||||
mirzaev\arming_bot\models\interfaces\document as arangodb_document_interface;
|
||||
mirzaev\arming_bot\models\interfaces\document as arangodb_document_interface,
|
||||
mirzaev\arming_bot\models\enumerations\language;
|
||||
|
||||
// Framework for ArangoDB
|
||||
use mirzaev\arangodb\collection,
|
||||
|
@ -51,7 +52,7 @@ final class settings extends core implements arangodb_document_interface
|
|||
// Initialized the collection
|
||||
|
||||
// Search for active settings
|
||||
$document = collection::execute(
|
||||
$result = collection::execute(
|
||||
<<<'AQL'
|
||||
FOR d IN @@collection
|
||||
FILTER d.status == 'active'
|
||||
|
@ -65,17 +66,24 @@ final class settings extends core implements arangodb_document_interface
|
|||
errors: $errors
|
||||
);
|
||||
|
||||
if ($document instanceof _document) {
|
||||
if ($result instanceof _document) {
|
||||
// Found active settings
|
||||
|
||||
// Initializing the implement object of the instance of settings document from ArangoDB
|
||||
// Initializing the object
|
||||
$settings = new static;
|
||||
|
||||
// Writing the instance of settings document from ArangoDB to the implement object
|
||||
$settings->__document($document);
|
||||
if (method_exists($settings, '__document')) {
|
||||
// Object can implement a document from ArangoDB
|
||||
|
||||
// Exit (success)
|
||||
return $settings;
|
||||
// Abstractioning of parameters
|
||||
$result->language = language::{$result->language} ?? 'en';
|
||||
|
||||
// Writing the instance of settings document from ArangoDB to the implement object
|
||||
$settings->__document($result);
|
||||
|
||||
// Exit (success)
|
||||
return $settings;
|
||||
}
|
||||
} else if ($create) {
|
||||
// Not found active settings and requested their creating
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@ namespace mirzaev\arming_bot\models;
|
|||
|
||||
// Files of the project
|
||||
use mirzaev\arming_bot\models\core,
|
||||
mirzaev\arming_bot\controllers\core as controller,
|
||||
mirzaev\arming_bot\models\settings,
|
||||
mirzaev\arming_bot\models\enumerations\language,
|
||||
mirzaev\arming_bot\models\traits\document as arangodb_document_trait,
|
||||
mirzaev\arming_bot\models\interfaces\document as arangodb_document_interface;
|
||||
|
||||
|
@ -53,7 +52,7 @@ final class suspension extends core implements arangodb_document_interface
|
|||
// Initialized the collection
|
||||
|
||||
// Search for active suspension
|
||||
$document = collection::execute(
|
||||
$result = collection::execute(
|
||||
<<<'AQL'
|
||||
FOR d IN @@collection
|
||||
FILTER d.end > @time
|
||||
|
@ -68,17 +67,21 @@ final class suspension extends core implements arangodb_document_interface
|
|||
errors: $errors
|
||||
);
|
||||
|
||||
if ($document instanceof _document) {
|
||||
// Found active suspension
|
||||
if ($result instanceof _document) {
|
||||
// Found active settings
|
||||
|
||||
// Initializing the implement object of the instance of suspension document from ArangoDB
|
||||
// Initializing the object
|
||||
$suspension = new static;
|
||||
|
||||
// Writing the instance of suspension document from ArangoDB to the implement object
|
||||
$suspension->__document($document);
|
||||
if (method_exists($suspension, '__document')) {
|
||||
// Object can implement a document from ArangoDB
|
||||
|
||||
// Exit (success)
|
||||
return $suspension;
|
||||
// Writing the instance of suspension document from ArangoDB to the implement object
|
||||
$suspension->__document($result);
|
||||
|
||||
// Exit (success)
|
||||
return $suspension;
|
||||
}
|
||||
} else return null;
|
||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||
} catch (exception $e) {
|
||||
|
@ -98,17 +101,14 @@ final class suspension extends core implements arangodb_document_interface
|
|||
/**
|
||||
* Generate message about remaining time
|
||||
*
|
||||
* @param string|null $language Language of the generated text (otherwise used from settings.language)
|
||||
* @param language|null $language Language of the generated text (otherwise used from settings.language)
|
||||
* @param array &$errors Registry of errors
|
||||
*
|
||||
* @return string|null Text: "? days, ? hours and ? minutes"
|
||||
*/
|
||||
public function message(?string $language = null, array &$errors = []): ?string
|
||||
public function message(?language $language = language::en, array &$errors = []): ?string
|
||||
{
|
||||
try {
|
||||
// Initializing default value
|
||||
$language ??= controller::$settings?->language ?? 'en';
|
||||
|
||||
// Initializing the time until the suspension ends
|
||||
$difference = date_diff(new datetime('@' . $this->document->end), new datetime());
|
||||
|
||||
|
@ -118,54 +118,54 @@ final class suspension extends core implements arangodb_document_interface
|
|||
$difference->d,
|
||||
match ($difference->d > 20 ? $difference->d % 10 : $difference->d % 100) {
|
||||
1 => match ($language) {
|
||||
'ru' => 'день',
|
||||
'en' => 'day',
|
||||
language::en => 'day',
|
||||
language::ru => 'день',
|
||||
default => 'day'
|
||||
},
|
||||
2, 3, 4 => match ($language) {
|
||||
'ru' => 'дня',
|
||||
'en' => 'days',
|
||||
language::en => 'days',
|
||||
language::ru => 'дня',
|
||||
default => 'days'
|
||||
},
|
||||
default => match ($language) {
|
||||
'ru' => 'дней',
|
||||
'en' => 'days',
|
||||
language::en => 'days',
|
||||
language::ru => 'дней',
|
||||
default => 'days'
|
||||
}
|
||||
},
|
||||
$difference->h,
|
||||
match ($difference->h > 20 ? $difference->h % 10 : $difference->h % 100) {
|
||||
1 => match ($language) {
|
||||
'ru' => 'час',
|
||||
'en' => 'hours',
|
||||
language::en => 'hours',
|
||||
language::ru => 'час',
|
||||
default => 'hour'
|
||||
},
|
||||
2, 3, 4 => match ($language) {
|
||||
'ru' => 'часа',
|
||||
'en' => 'hours',
|
||||
language::en => 'hours',
|
||||
language::ru => 'часа',
|
||||
default => 'hours'
|
||||
},
|
||||
default => match ($language) {
|
||||
'ru' => 'часов',
|
||||
'en' => 'hours',
|
||||
language::en => 'hours',
|
||||
language::ru => 'часов',
|
||||
default => 'hours'
|
||||
}
|
||||
},
|
||||
$difference->i,
|
||||
match ($difference->i > 20 ? $difference->i % 10 : $difference->i % 100) {
|
||||
1 => match ($language) {
|
||||
'ru' => 'минута',
|
||||
'en' => 'minute',
|
||||
language::en => 'minute',
|
||||
language::ru => 'минута',
|
||||
default => 'minute'
|
||||
},
|
||||
2, 3, 4 => match ($language) {
|
||||
'ru' => 'минуты',
|
||||
'en' => 'minutes',
|
||||
language::en => 'minutes',
|
||||
language::ru => 'минуты',
|
||||
default => 'minutes'
|
||||
},
|
||||
default => match ($language) {
|
||||
'ru' => 'минут',
|
||||
'en' => 'minutes',
|
||||
language::en => 'minutes',
|
||||
language::ru => 'минут',
|
||||
default => 'minutes'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -410,7 +410,7 @@ final class telegram extends core
|
|||
$products_deleted,
|
||||
$products_old,
|
||||
$products_new,
|
||||
language: 'ru'
|
||||
language: $account->language ?? settings::active()?->language ?? 'en'
|
||||
);
|
||||
|
||||
// Отправка сообщения
|
||||
|
@ -489,7 +489,7 @@ final class telegram extends core
|
|||
$telegram = $ctx->getEffectiveUser();
|
||||
|
||||
// Инициализация аккаунта
|
||||
$account = account::initialization($telegram->getId(), $telegram);
|
||||
$account = account::initialize($telegram->getId(), $telegram);
|
||||
|
||||
if ($account) {
|
||||
// Инициализирован аккаунт
|
||||
|
@ -561,11 +561,11 @@ final class telegram extends core
|
|||
}
|
||||
|
||||
// Инициализация сообщения
|
||||
$message = "⚠️ *Работа приостановлена*\n*Оставшееся время\:* " . $suspension->message($account->language ?? controller::$settings?->language);
|
||||
$message = "⚠️ *Работа приостановлена*\n*Оставшееся время\:* " . $suspension->message($account->language ?? settings::active()?->language ?? 'en');
|
||||
|
||||
// Добавление описания причины приостановки, если найдена
|
||||
if (!empty($suspension->description))
|
||||
$message .= "\n\n" . $suspension->description[$account->language ?? controller::$settings?->language] ?? array_values($suspension->description)[0];
|
||||
$message .= "\n\n" . $suspension->description[$account->language ?? settings::active()?->language ?? 'en'] ?? array_values($suspension->description)[0];
|
||||
|
||||
// Отправка сообщения
|
||||
$ctx->sendMessage($message)
|
||||
|
|
|
@ -49,7 +49,7 @@ trait document
|
|||
parent::__construct($initialize, $arangodb);
|
||||
|
||||
// Writing to the property
|
||||
if ($document instanceof _document) $this->document = $document;
|
||||
if ($document instanceof _document) $this->__document($document);
|
||||
else if ($document === null) throw new exception('Failed to initialize an instance of the document from ArangoDB');
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,6 @@ trait document
|
|||
{
|
||||
// Read a property from an instance of the ArangoDB document and exit (success)
|
||||
return match ($name) {
|
||||
'arangodb' => core::$arangodb,
|
||||
default => $this->document->{$name}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -41,8 +41,9 @@ $router
|
|||
->write('/', 'catalog', 'index', 'GET')
|
||||
->write('/search', 'catalog', 'search', 'POST')
|
||||
->write('/session/connect/telegram', 'session', 'telegram', 'POST')
|
||||
->write('/product/$id', 'catalog', 'product', 'POST')
|
||||
->write('/$categories...', 'catalog', 'index', 'POST');
|
||||
->write('/category/$identifier', 'catalog', 'index', 'POST')
|
||||
->write('/category', 'catalog', 'index', 'POST')
|
||||
->write('/product/$identifier', 'catalog', 'product', 'POST');
|
||||
|
||||
/*
|
||||
|
||||
|
|
|
@ -34,16 +34,11 @@ import("/js/core.js").then(() =>
|
|||
|
||||
// Write to the core
|
||||
core.catalog = class catalog {
|
||||
/**
|
||||
* Current position in hierarchy of the categories
|
||||
*/
|
||||
static categories = [];
|
||||
|
||||
/**
|
||||
* Registry of filters (instead of cookies)
|
||||
*/
|
||||
static filters = new Map([
|
||||
['brand', null]
|
||||
["brand", null],
|
||||
]);
|
||||
|
||||
/**
|
||||
|
@ -56,10 +51,12 @@ import("/js/core.js").then(() =>
|
|||
* @return {void}
|
||||
*/
|
||||
static category(button, clean = true, force = false) {
|
||||
// Initialize of the new category name
|
||||
const category = button.getAttribute("data-category-name");
|
||||
// Initializing identifier of the category
|
||||
const identifier = button.getAttribute(
|
||||
"data-category-identifier",
|
||||
);
|
||||
|
||||
this._category(category, clean, force);
|
||||
this._category(identifier, clean, force);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,22 +77,22 @@ import("/js/core.js").then(() =>
|
|||
/**
|
||||
* Select a category (system)
|
||||
*
|
||||
* @param {HTMLElement} button Button of category <a>
|
||||
* @param {string} identifier Identifier of the category
|
||||
* @param {bool} clean Clear search bar?
|
||||
*
|
||||
* @return {Promise} Request to the server
|
||||
*/
|
||||
static __category(category = "", clean = true) {
|
||||
static __category(category, clean = true) {
|
||||
if (typeof category === "string") {
|
||||
//
|
||||
// Received required parameters
|
||||
|
||||
let urn;
|
||||
if (category === "/" || category === "") urn = "/";
|
||||
else {urn = this.categories.length > 0
|
||||
? `/${this.categories.join("/")}/${category}`
|
||||
: `/${category}`;}
|
||||
|
||||
return core.request(urn)
|
||||
return core.request(
|
||||
"/category" +
|
||||
("/" + category).replace(/^\/*/, "/").trim().replace(
|
||||
/\/*$/,
|
||||
"",
|
||||
),
|
||||
)
|
||||
.then((json) => {
|
||||
if (
|
||||
json.errors !== null &&
|
||||
|
@ -114,11 +111,6 @@ import("/js/core.js").then(() =>
|
|||
if (search instanceof HTMLElement) search.value = "";
|
||||
}
|
||||
|
||||
// Write the category to position in the categories hierarchy
|
||||
if (category !== "/" && category !== "") {
|
||||
this.categories.push(category);
|
||||
}
|
||||
|
||||
if (
|
||||
typeof json.title === "string" &&
|
||||
json.title.length > 0
|
||||
|
@ -288,9 +280,6 @@ import("/js/core.js").then(() =>
|
|||
* @todo add animations of errors
|
||||
*/
|
||||
static __search(element) {
|
||||
// Deinitialization of position in the categories hierarchy
|
||||
this.categories = [];
|
||||
|
||||
return this.__category("/", false)
|
||||
.then(function () {
|
||||
core.request("/search", `text=${element.value}`)
|
||||
|
@ -392,19 +381,19 @@ import("/js/core.js").then(() =>
|
|||
/**
|
||||
* Open product card (interface)
|
||||
*
|
||||
* @param {string} id Identifier of a product
|
||||
* @param {string} identifier Identifier of a product
|
||||
* @param {bool} force Ignore the damper?
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
static product(id, force = false) {
|
||||
this._product(id, force);
|
||||
static product(identifier, force = false) {
|
||||
this._product(identifier, force);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open product card (damper)
|
||||
*
|
||||
* @param {string} id Identifier of a product
|
||||
* @param {string} identifier Identifier of a product
|
||||
* @param {bool} force Ignore the damper?
|
||||
*
|
||||
* @return {void}
|
||||
|
@ -418,15 +407,15 @@ import("/js/core.js").then(() =>
|
|||
/**
|
||||
* Open product card (system)
|
||||
*
|
||||
* @param {string} id Identifier of a product
|
||||
* @param {string} identifier Identifier of a product
|
||||
*
|
||||
* @return {Promise} Request to the server
|
||||
*/
|
||||
static __product(id) {
|
||||
if (typeof id === "number") {
|
||||
static __product(identifier) {
|
||||
if (typeof identifier === "number") {
|
||||
//
|
||||
|
||||
return core.request(`/product/${id}`)
|
||||
return core.request(`/product/${identifier}`)
|
||||
.then((json) => {
|
||||
if (
|
||||
json.errors !== null &&
|
||||
|
@ -455,15 +444,18 @@ import("/js/core.js").then(() =>
|
|||
card.classList.add("card", "unselectable");
|
||||
|
||||
const h3 = document.createElement("h3");
|
||||
h3.setAttribute("title", json.product.id);
|
||||
|
||||
const title = document.createElement("span");
|
||||
title.classList.add("title");
|
||||
title.innerText = json.product.title;
|
||||
const name = document.createElement("span");
|
||||
name.classList.add("name");
|
||||
name.setAttribute("title", json.product.identifier);
|
||||
name.innerText = json.product.name;
|
||||
|
||||
const brand = document.createElement("small");
|
||||
brand.classList.add("brand");
|
||||
brand.innerText = json.product.brand;
|
||||
const exit = document.createElement("a");
|
||||
exit.classList.add("exit");
|
||||
exit.setAttribute("type", "button");
|
||||
|
||||
const exit_icon = document.createElement("i");
|
||||
exit_icon.classList.add("icon", "close");
|
||||
|
||||
const images = document.createElement("div");
|
||||
images.classList.add("images", "unselectable");
|
||||
|
@ -528,6 +520,13 @@ import("/js/core.js").then(() =>
|
|||
images.append(image);
|
||||
}
|
||||
|
||||
const header = document.createElement("p");
|
||||
header.classList.add('header');
|
||||
|
||||
const brand = document.createElement("small");
|
||||
brand.classList.add("brand");
|
||||
brand.innerText = json.product.brand;
|
||||
|
||||
const description = document.createElement("p");
|
||||
description.classList.add("description");
|
||||
description.innerText = json.product.description;
|
||||
|
@ -542,10 +541,24 @@ import("/js/core.js").then(() =>
|
|||
|
||||
const dimensions = document.createElement("small");
|
||||
dimensions.classList.add("dimensions");
|
||||
dimensions.innerText = json.product.dimensions.x +
|
||||
"x" +
|
||||
json.product.dimensions.y + "x" +
|
||||
json.product.dimensions.z;
|
||||
|
||||
const x = json.product.dimensions.x;
|
||||
const y = json.product.dimensions.y;
|
||||
const z = json.product.dimensions.z;
|
||||
|
||||
let formatted = "";
|
||||
|
||||
if (x !== '' ) formatted = x;
|
||||
if (y !== '') {
|
||||
if (formatted.length === 0) formatted = y;
|
||||
else formatted += "x" + y;
|
||||
}
|
||||
if (z !== '') {
|
||||
if (formatted.length === 0) formatted = z;
|
||||
else formatted += "x" + z;
|
||||
}
|
||||
|
||||
dimensions.innerText = formatted;
|
||||
|
||||
const weight = document.createElement("small");
|
||||
weight.classList.add("weight");
|
||||
|
@ -555,10 +568,13 @@ import("/js/core.js").then(() =>
|
|||
cost.classList.add("cost");
|
||||
cost.innerText = json.product.cost + "р";
|
||||
|
||||
h3.append(title);
|
||||
h3.append(brand);
|
||||
h3.append(name);
|
||||
exit.append(exit_icon);
|
||||
h3.append(exit);
|
||||
card.append(h3);
|
||||
card.append(images);
|
||||
header.append(brand);
|
||||
card.append(header);
|
||||
card.append(description);
|
||||
card.append(compatibility);
|
||||
footer.append(dimensions);
|
||||
|
@ -581,8 +597,8 @@ import("/js/core.js").then(() =>
|
|||
);
|
||||
|
||||
history.pushState(
|
||||
{ product_card: json.product.id },
|
||||
json.product.title,
|
||||
{ product_card: json.product.identifier },
|
||||
json.product.name,
|
||||
);
|
||||
|
||||
// блокировка закрытия карточки
|
||||
|
@ -595,6 +611,8 @@ import("/js/core.js").then(() =>
|
|||
wrap.remove();
|
||||
wrap.removeEventListener("mousedown", _from);
|
||||
wrap.removeEventListener("touchstart", _from);
|
||||
exit.removeEventListener("click", remove);
|
||||
exit.removeEventListener("touch", remove);
|
||||
document.removeEventListener("click", close);
|
||||
document.removeEventListener("touch", close);
|
||||
window.removeEventListener("popstate", remove);
|
||||
|
@ -615,13 +633,15 @@ import("/js/core.js").then(() =>
|
|||
from = undefined;
|
||||
};
|
||||
|
||||
exit.addEventListener("click", remove);
|
||||
exit.addEventListener("touch", remove);
|
||||
document.addEventListener("click", close);
|
||||
document.addEventListener("touch", close);
|
||||
window.addEventListener("popstate", remove);
|
||||
|
||||
if (width > card.offsetWidth) {
|
||||
images.hotline = new core.hotline(
|
||||
json.product.id,
|
||||
json.product.identfier,
|
||||
images,
|
||||
);
|
||||
images.hotline.step = -0.3;
|
||||
|
|
|
@ -8,9 +8,10 @@ main>section[data-section="catalog"] {
|
|||
}
|
||||
|
||||
main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[type="button"] {
|
||||
--padding: 0.7rem;
|
||||
position: relative;
|
||||
height: 23px;
|
||||
padding: unset;
|
||||
padding: var(--padding);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
@ -27,7 +28,9 @@ main>section[data-section="catalog"][data-catalog-type="categories"]:last-child
|
|||
}
|
||||
|
||||
main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[type="button"]:has(>img) {
|
||||
min-width: calc(50% - var(--padding) * 2);
|
||||
height: 180px;
|
||||
padding: unset;
|
||||
}
|
||||
|
||||
main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[type="button"]>img {
|
||||
|
@ -37,7 +40,8 @@ main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[
|
|||
width: 110%;
|
||||
height: 110%;
|
||||
object-fit: cover;
|
||||
filter: blur(1px);
|
||||
/* filter: blur(1px); */
|
||||
filter: brightness(60%);
|
||||
}
|
||||
|
||||
main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[type="button"]:hover>img {
|
||||
|
@ -45,14 +49,12 @@ main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[
|
|||
}
|
||||
|
||||
main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[type="button"]:has(>img)>p {
|
||||
--padding: 0.7rem;
|
||||
position: absolute;
|
||||
left: var(--padding);
|
||||
bottom: var(--padding);
|
||||
right: var(--padding);
|
||||
margin: unset;
|
||||
width: min-content;
|
||||
padding: var(--padding);
|
||||
border-radius: 0.75rem;
|
||||
background: var(--tg-theme-secondary-bg-color);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
@charset "UTF-8";
|
||||
|
||||
i.icon.close {
|
||||
--diameter: 22px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
display: block;
|
||||
width: var(--diameter);
|
||||
height: var(--diameter);
|
||||
border: 2px solid transparent;
|
||||
border-radius: 40px;
|
||||
}
|
||||
i.icon.close::after,
|
||||
i.icon.close::before {
|
||||
content: "";
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
height: 2px;
|
||||
background: currentColor;
|
||||
transform: rotate(45deg);
|
||||
border-radius: 5px;
|
||||
top: 8px;
|
||||
left: 1px;
|
||||
}
|
||||
i.icon.close::after {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
|
@ -108,12 +108,15 @@ search:has(input:disabled) {
|
|||
backdrop-filter: contrast(0.5);
|
||||
}
|
||||
|
||||
*[type="button"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:is(button, a[type="button"]) {
|
||||
padding: 8px 16px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
color: var(--tg-theme-button-text-color);
|
||||
background-color: var(--tg-theme-button-color);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
section#window {
|
||||
z-index: 1500;
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
|
@ -24,7 +24,7 @@ section#window>div.card {
|
|||
section#window>div.card>h3 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
height: 23px;
|
||||
padding: 1rem 1.5rem;
|
||||
padding: 1rem 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
|
@ -32,16 +32,29 @@ section#window>div.card>h3 {
|
|||
background-color: var(--tg-theme-header-bg-color);
|
||||
}
|
||||
|
||||
section#window>div.card>h3>span.title {
|
||||
section#window>div.card>h3>span.name {
|
||||
margin-left: 1.5rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
section#window>div.card>h3>small.brand {
|
||||
/* section#window>div.card>h3>small.brand {
|
||||
margin-left: auto;
|
||||
font-size: 0.8rem;
|
||||
font-weight: normal;
|
||||
color: var(--tg-theme-section-header-text-color);
|
||||
} */
|
||||
|
||||
section#window>div.card>h3>a.exit[type="button"] {
|
||||
margin-left: auto;
|
||||
margin-right: 0.5rem;
|
||||
padding: 0.6rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
color: var(--tg-theme-section-header-text-color);
|
||||
background-color: unset;
|
||||
}
|
||||
|
||||
section#window>div.card>div.images {
|
||||
|
@ -102,7 +115,7 @@ section#window>div.card>p {
|
|||
min-height: 1rem;
|
||||
padding: 0 1rem;
|
||||
overflow-y: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
section#window>div.card>p:last-of-type {
|
||||
|
|
|
@ -16,7 +16,8 @@ use mirzaev\minimal\controller;
|
|||
use Twig\Loader\FilesystemLoader,
|
||||
Twig\Environment as twig,
|
||||
Twig\Extra\Intl\IntlExtension as intl,
|
||||
Twig\TwigFilter;
|
||||
Twig\TwigFilter,
|
||||
Twig\TwigFunction;
|
||||
|
||||
|
||||
// Built-in libraries
|
||||
|
@ -43,13 +44,17 @@ final class templater extends controller implements ArrayAccess
|
|||
/**
|
||||
* Constructor of an instance
|
||||
*
|
||||
* @param session|null $session An object implementing a session instance from ArangoDB
|
||||
* @param account|null $account An object implementing an account instance from ArangoDB
|
||||
* @param session|null $session The object implementing a session instance from ArangoDB
|
||||
* @param account|null $account The object implementing an account instance from ArangoDB
|
||||
* @param settings|null $settings The object implementing an account instance from ArangoDB
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(?session $session = null, ?account $account = null)
|
||||
{
|
||||
public function __construct(
|
||||
?session $session = null,
|
||||
?account $account = null,
|
||||
?settings $settings = null
|
||||
) {
|
||||
// Initializing of an instance of twig
|
||||
$this->twig = new twig(new FilesystemLoader(VIEWS));
|
||||
|
||||
|
@ -57,9 +62,41 @@ final class templater extends controller implements ArrayAccess
|
|||
$this->twig->addGlobal('theme', 'default');
|
||||
$this->twig->addGlobal('server', $_SERVER);
|
||||
$this->twig->addGlobal('cookies', $_COOKIE);
|
||||
$this->twig->addGlobal('settings', settings::active());
|
||||
$this->twig->addGlobal('settings', $settings);
|
||||
if (!empty($session?->status())) $this->twig->addGlobal('session', $session);
|
||||
if (!empty($account?->status())) $this->twig->addGlobal('account', $account);
|
||||
$this->twig->addGlobal('language', $account?->language->name ?? $settings?->language->name ?? 'en');
|
||||
|
||||
|
||||
// Initialize function of dimensions formattinx
|
||||
$this->twig->addFunction(
|
||||
new TwigFunction(
|
||||
'format_dimensions',
|
||||
function (
|
||||
string|int|float|null $x = null,
|
||||
string|int|float|null $y = null,
|
||||
string|int|float|null $z = null,
|
||||
string|null $before = null,
|
||||
string|null $after = null
|
||||
) {
|
||||
// Initialzing the buffer of result
|
||||
$result = '';
|
||||
|
||||
// Generating
|
||||
if (!empty($x)) $result .= $x;
|
||||
if (!empty($y))
|
||||
if (empty($result)) $result = "$y";
|
||||
else $result .= "x$y";
|
||||
if (!empty($z))
|
||||
if (empty($result)) $result = "$z";
|
||||
else $result .= "x$z";
|
||||
if (!empty($result)) $result = "$before$result$after";
|
||||
|
||||
// Exit (success)
|
||||
return $result;
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Initializing of twig extensions
|
||||
$this->twig->addExtension(new intl());
|
||||
|
|
|
@ -2,11 +2,19 @@
|
|||
<section class="unselectable" data-section="catalog" data-catalog-type="categories"
|
||||
data-catalog-level="{{ level ?? 0 }}">
|
||||
{% for category in categories %}
|
||||
{% if category.images %}
|
||||
<a id="{{ category.getId() }}" class="category" type="button" onclick="return core.catalog.category(this);"
|
||||
data-category-identifier="{{ category.identifier }}">
|
||||
<img src="{{ category.images.0.storage }}" alt="{{ category.name[ account.language ?? settings.language ?? 'en' ] }}" ondrugstart="return false;">
|
||||
<p>{{ category.name[ account.language ?? settings.language ?? 'en' ] }}</p>
|
||||
<img src="{{ category.images.0.storage }}"
|
||||
alt="{{ category.name[language] }}" ondrugstart="return false;">
|
||||
<p>{{ category.name[language] }}</p>
|
||||
</a>
|
||||
{% else %}
|
||||
<a id="{{ category.getId() }}" class="category" type="button" onclick="return core.catalog.category(this);"
|
||||
data-category-identifier="{{ category.identifier }}">
|
||||
<p>{{ category.name[language] }}</p>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
{% macro card(product) %}
|
||||
{% set title = product.title.ru ~ ' ' ~ product.brand.ru ~ ' ' ~ product.dimensions.x ~ 'x' ~ product.dimensions.y ~ 'x'
|
||||
~ product.dimensions.z ~ ' ' ~ product.weight ~ 'г' %}
|
||||
{% set title = product.name[language] ~ ' ' ~ product.brand[language] ~ format_dimensions(product.dimensions.x, product.dimensions.y, product.dimensions.z, ' ') ~ ' ' ~ product.weight ~ 'г' %}
|
||||
<article id="{{ product.getId() }}" class="product unselectable">
|
||||
<a onclick="core.catalog.product({{ product.getKey() }})">
|
||||
<img src="{{ product.images.0.storage }}" alt="{{ product.title.ru }}" ondrugstart="return false;">
|
||||
<p class="title" title="{{ product.title.ru }}">
|
||||
<a onclick="core.catalog.product({{ product.identifier }})">
|
||||
<img src="{{ product.images.0.storage }}" alt="{{ product.name[language] }}" ondrugstart="return false;">
|
||||
<p class="title" title="{{ product.name[language] }}">
|
||||
{{ title | length > 45 ? title | slice(0, 45) ~ '...' : title }}
|
||||
</p>
|
||||
</a>
|
||||
|
@ -13,7 +12,6 @@
|
|||
</button>
|
||||
</article>
|
||||
{% endmacro %}
|
||||
|
||||
{% if products is not empty %}
|
||||
<section class="unselectable" data-section="catalog" data-catalog-type="products" data-catalog-level="{{ level ?? 0 }}">
|
||||
<div class="column">
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/catalog/2columns.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/search.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/shopping_cart.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/close.css" />
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
|
Loading…
Reference in New Issue