import from excel + broken dependencies see next commit
This commit is contained in:
parent
f69d6ae96c
commit
af48d505bf
71
README.md
71
README.md
|
@ -6,39 +6,36 @@ Basis for developing chat-robots with "Web App" technology for Telegram
|
||||||
|
|
||||||
### AnangoDB
|
### AnangoDB
|
||||||
|
|
||||||
1. Create a View in ArangoDB for the document "product"
|
1. Create a Graph with the specified values
|
||||||
`
|
**Name:** catalog
|
||||||
"links": {
|
|
||||||
"product": {
|
|
||||||
"fields": {
|
|
||||||
"description": {
|
|
||||||
"analyzers": [
|
|
||||||
"text_ru"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
2. Create a Graph with the specified values
|
|
||||||
**Name:** hierarchy
|
|
||||||
|
|
||||||
**edgeDefinition:** entry
|
**edgeDefinition:** entry
|
||||||
**fromCollections:** part, product...
|
**fromCollections:** categoy, product
|
||||||
**toCollections:** category, part...
|
**toCollections:** category
|
||||||
|
|
||||||
|
2. Create a Graph with the specified values
|
||||||
|
**Name:** sessions
|
||||||
|
|
||||||
|
**edgeDefinition:** connect
|
||||||
|
**fromCollections:** account
|
||||||
|
**toCollections:** session
|
||||||
|
|
||||||
3. Create indexes for the "product" collection
|
3. Create indexes for the "product" collection
|
||||||
**Type:** "Inverted Index"
|
**Type:** "Inverted Index"
|
||||||
**Fields:** title.RU
|
**Fields:** name.ru
|
||||||
**Analyzer:** "text_ru"
|
**Analyzer:** "text_ru"
|
||||||
**Search field:** true
|
**Search field:** true
|
||||||
**Name:** title_ru
|
**Name:** name_ru
|
||||||
|
|
||||||
|
*Add indexes for all search parameters and for all languages (search language is selected based on the user's language,
|
||||||
|
otherwise from the default language specified in the active settings from **settings** collection document)*
|
||||||
|
|
||||||
|
*See fields in the `mirzaev/arming_bot/models/product`
|
||||||
|
**name.ru**, **description.ru** and **compatibility.ru***
|
||||||
|
|
||||||
4. Create a View with the specified values
|
4. Create a View with the specified values
|
||||||
**Name:** products_search
|
|
||||||
|
|
||||||
**type:** search-alias (you can also use "arangosearch")
|
**type:** search-alias (you can also use "arangosearch")
|
||||||
|
**name:** **product**s_search
|
||||||
**indexes:**
|
**indexes:**
|
||||||
`
|
`
|
||||||
"indexes": [
|
"indexes": [
|
||||||
|
@ -51,19 +48,33 @@ Basis for developing chat-robots with "Web App" technology for Telegram
|
||||||
|
|
||||||
### NGINX
|
### NGINX
|
||||||
|
|
||||||
1. Add this to a NGINX config: `try_files $uri $uri/ /index.php;`
|
1. Example of NGINX server file
|
||||||
|
|
||||||
2. Add this to a NGINX config
|
|
||||||
`
|
`
|
||||||
location /images {
|
location / {
|
||||||
alias /PATH/TO/public/themes/default/images;
|
try_files $uri $uri/ /index.php;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ /(?<type>categories|products) {
|
||||||
|
root /var/www/arming_bot/mirzaev/arming_bot/system/storage;
|
||||||
|
try_files $uri =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.php$ {
|
||||||
|
...
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
### SystemD (or any alternative you like)
|
||||||
|
|
||||||
|
1. Execute: `sudo cp telegram-huesos.service /etc/systemd/system/telegram-huesos.service`
|
||||||
|
|
||||||
|
*before you execute the command think about **what it does** and whether the **paths** are specified correctly*
|
||||||
|
*the configuration file is very simple and you can remake it for any alternative to SystemD that you like*
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
Settings of chat-robot and Web App
|
Settings of chat-robot and Web App
|
||||||
|
|
||||||
Make sure you have a "settings" collection (can be created automatically) and at least one document with the "status" parameter set to "active"
|
Make sure you have a **settings** collection (can be created automatically) and at least one document with the "status" parameter set to "active"
|
||||||
`
|
`
|
||||||
{
|
{
|
||||||
"status": "active"
|
"status": "active"
|
||||||
|
@ -78,7 +89,7 @@ Language for system messages if user language could not be determined
|
||||||
## Suspensions
|
## Suspensions
|
||||||
System of suspensions of chat-robot and Web App
|
System of suspensions of chat-robot and Web App
|
||||||
|
|
||||||
Make sure you have a "suspension" collection (can be created automatically)
|
Make sure you have a **suspension** collection (can be created automatically)
|
||||||
`
|
`
|
||||||
{
|
{
|
||||||
"end": 1726068961,
|
"end": 1726068961,
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"twig/twig": "^3.10",
|
"twig/twig": "^3.10",
|
||||||
"twig/extra-bundle": "^3.7",
|
"twig/extra-bundle": "^3.7",
|
||||||
"twig/intl-extra": "^3.10",
|
"twig/intl-extra": "^3.10",
|
||||||
"phpoffice/phpspreadsheet": "^2.1"
|
"avadim/fast-excel-reader": "^2.19"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|
|
@ -4,8 +4,120 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "61697600b2677e22a6133cff9768d9eb",
|
"content-hash": "e580e133abf1c4a60898f255e006a3e9",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "avadim/fast-excel-helper",
|
||||||
|
"version": "v1.2.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/aVadim483/fast-excel-helper.git",
|
||||||
|
"reference": "2792c4a20b529b537ede7148e2c29dc4677818db"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/aVadim483/fast-excel-helper/zipball/2792c4a20b529b537ede7148e2c29dc4677818db",
|
||||||
|
"reference": "2792c4a20b529b537ede7148e2c29dc4677818db",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-ctype": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"php": ">=7.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"avadim\\FastExcelHelper\\": "./src/FastExcelHelper"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"description": "Helper for avadim/fast-excel-reader and avadim/fast-excel-writer",
|
||||||
|
"homepage": "https://github.com/aVadim483/fast-excel-helper",
|
||||||
|
"keywords": [
|
||||||
|
"MS Office",
|
||||||
|
"PHPExcel",
|
||||||
|
"excel",
|
||||||
|
"library",
|
||||||
|
"office 2007",
|
||||||
|
"parser",
|
||||||
|
"php",
|
||||||
|
"reader",
|
||||||
|
"spreadsheet",
|
||||||
|
"writer",
|
||||||
|
"xlsx"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/aVadim483/fast-excel-helper/issues",
|
||||||
|
"source": "https://github.com/aVadim483/fast-excel-helper/tree/v1.2.1"
|
||||||
|
},
|
||||||
|
"time": "2024-09-06T20:37:07+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "avadim/fast-excel-reader",
|
||||||
|
"version": "v2.19.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/aVadim483/fast-excel-reader.git",
|
||||||
|
"reference": "e2fa125a93c0c5115344ebab1a36b81cd2be63c8"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/aVadim483/fast-excel-reader/zipball/e2fa125a93c0c5115344ebab1a36b81cd2be63c8",
|
||||||
|
"reference": "e2fa125a93c0c5115344ebab1a36b81cd2be63c8",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"avadim/fast-excel-helper": "^1.1",
|
||||||
|
"ext-ctype": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-xmlreader": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"php": ">=7.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"avadim\\FastExcelReader\\": "./src/FastExcelReader"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"description": "Lightweight and very fast XLSX Excel Spreadsheet Reader in PHP",
|
||||||
|
"homepage": "https://github.com/aVadim483/fast-excel-reader",
|
||||||
|
"keywords": [
|
||||||
|
"MS Office",
|
||||||
|
"PHPExcel",
|
||||||
|
"excel",
|
||||||
|
"import",
|
||||||
|
"library",
|
||||||
|
"office 2007",
|
||||||
|
"parser",
|
||||||
|
"php",
|
||||||
|
"reader",
|
||||||
|
"spreadsheet",
|
||||||
|
"xls",
|
||||||
|
"xlsx"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/aVadim483/fast-excel-reader/issues",
|
||||||
|
"source": "https://github.com/aVadim483/fast-excel-reader/tree/v2.19.0"
|
||||||
|
},
|
||||||
|
"time": "2024-09-22T19:34:27+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "badfarm/zanzara",
|
"name": "badfarm/zanzara",
|
||||||
"version": "0.9.1",
|
"version": "0.9.1",
|
||||||
|
@ -584,194 +696,6 @@
|
||||||
},
|
},
|
||||||
"time": "2024-08-02T07:48:17+00:00"
|
"time": "2024-08-02T07:48:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "maennchen/zipstream-php",
|
|
||||||
"version": "3.1.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/maennchen/ZipStream-PHP.git",
|
|
||||||
"reference": "b8174494eda667f7d13876b4a7bfef0f62a7c0d1"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/b8174494eda667f7d13876b4a7bfef0f62a7c0d1",
|
|
||||||
"reference": "b8174494eda667f7d13876b4a7bfef0f62a7c0d1",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-mbstring": "*",
|
|
||||||
"ext-zlib": "*",
|
|
||||||
"php-64bit": "^8.1"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"ext-zip": "*",
|
|
||||||
"friendsofphp/php-cs-fixer": "^3.16",
|
|
||||||
"guzzlehttp/guzzle": "^7.5",
|
|
||||||
"mikey179/vfsstream": "^1.6",
|
|
||||||
"php-coveralls/php-coveralls": "^2.5",
|
|
||||||
"phpunit/phpunit": "^10.0",
|
|
||||||
"vimeo/psalm": "^5.0"
|
|
||||||
},
|
|
||||||
"suggest": {
|
|
||||||
"guzzlehttp/psr7": "^2.4",
|
|
||||||
"psr/http-message": "^2.0"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"ZipStream\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Paul Duncan",
|
|
||||||
"email": "pabs@pablotron.org"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Jonatan Männchen",
|
|
||||||
"email": "jonatan@maennchen.ch"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Jesse Donat",
|
|
||||||
"email": "donatj@gmail.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "András Kolesár",
|
|
||||||
"email": "kolesar@kolesar.hu"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.",
|
|
||||||
"keywords": [
|
|
||||||
"stream",
|
|
||||||
"zip"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/maennchen/ZipStream-PHP/issues",
|
|
||||||
"source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.0"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://github.com/maennchen",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://opencollective.com/zipstream",
|
|
||||||
"type": "open_collective"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2023-06-21T14:59:35+00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "markbaker/complex",
|
|
||||||
"version": "3.0.2",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/MarkBaker/PHPComplex.git",
|
|
||||||
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
|
|
||||||
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": "^7.2 || ^8.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
|
|
||||||
"phpcompatibility/php-compatibility": "^9.3",
|
|
||||||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
|
|
||||||
"squizlabs/php_codesniffer": "^3.7"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Complex\\": "classes/src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Mark Baker",
|
|
||||||
"email": "mark@lange.demon.co.uk"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "PHP Class for working with complex numbers",
|
|
||||||
"homepage": "https://github.com/MarkBaker/PHPComplex",
|
|
||||||
"keywords": [
|
|
||||||
"complex",
|
|
||||||
"mathematics"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
|
|
||||||
"source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2"
|
|
||||||
},
|
|
||||||
"time": "2022-12-06T16:21:08+00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "markbaker/matrix",
|
|
||||||
"version": "3.0.1",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/MarkBaker/PHPMatrix.git",
|
|
||||||
"reference": "728434227fe21be27ff6d86621a1b13107a2562c"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c",
|
|
||||||
"reference": "728434227fe21be27ff6d86621a1b13107a2562c",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": "^7.1 || ^8.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
|
|
||||||
"phpcompatibility/php-compatibility": "^9.3",
|
|
||||||
"phpdocumentor/phpdocumentor": "2.*",
|
|
||||||
"phploc/phploc": "^4.0",
|
|
||||||
"phpmd/phpmd": "2.*",
|
|
||||||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
|
|
||||||
"sebastian/phpcpd": "^4.0",
|
|
||||||
"squizlabs/php_codesniffer": "^3.7"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Matrix\\": "classes/src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Mark Baker",
|
|
||||||
"email": "mark@demon-angel.eu"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "PHP Class for working with matrices",
|
|
||||||
"homepage": "https://github.com/MarkBaker/PHPMatrix",
|
|
||||||
"keywords": [
|
|
||||||
"mathematics",
|
|
||||||
"matrix",
|
|
||||||
"vector"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
|
|
||||||
"source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1"
|
|
||||||
},
|
|
||||||
"time": "2022-12-02T22:17:43+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "mirzaev/arangodb",
|
"name": "mirzaev/arangodb",
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
|
@ -1417,110 +1341,6 @@
|
||||||
},
|
},
|
||||||
"time": "2024-09-04T13:22:54+00:00"
|
"time": "2024-09-04T13:22:54+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "phpoffice/phpspreadsheet",
|
|
||||||
"version": "2.2.2",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
|
|
||||||
"reference": "ffbcee68069b073bff07a71eb321dcd9f2763513"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/ffbcee68069b073bff07a71eb321dcd9f2763513",
|
|
||||||
"reference": "ffbcee68069b073bff07a71eb321dcd9f2763513",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-ctype": "*",
|
|
||||||
"ext-dom": "*",
|
|
||||||
"ext-fileinfo": "*",
|
|
||||||
"ext-gd": "*",
|
|
||||||
"ext-iconv": "*",
|
|
||||||
"ext-libxml": "*",
|
|
||||||
"ext-mbstring": "*",
|
|
||||||
"ext-simplexml": "*",
|
|
||||||
"ext-xml": "*",
|
|
||||||
"ext-xmlreader": "*",
|
|
||||||
"ext-xmlwriter": "*",
|
|
||||||
"ext-zip": "*",
|
|
||||||
"ext-zlib": "*",
|
|
||||||
"maennchen/zipstream-php": "^2.1 || ^3.0",
|
|
||||||
"markbaker/complex": "^3.0",
|
|
||||||
"markbaker/matrix": "^3.0",
|
|
||||||
"php": "^8.1",
|
|
||||||
"psr/http-client": "^1.0",
|
|
||||||
"psr/http-factory": "^1.0",
|
|
||||||
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"dealerdirect/phpcodesniffer-composer-installer": "dev-main",
|
|
||||||
"dompdf/dompdf": "^2.0 || ^3.0",
|
|
||||||
"friendsofphp/php-cs-fixer": "^3.2",
|
|
||||||
"mitoteam/jpgraph": "^10.3",
|
|
||||||
"mpdf/mpdf": "^8.1.1",
|
|
||||||
"phpcompatibility/php-compatibility": "^9.3",
|
|
||||||
"phpstan/phpstan": "^1.1",
|
|
||||||
"phpstan/phpstan-phpunit": "^1.0",
|
|
||||||
"phpunit/phpunit": "^9.6 || ^10.5",
|
|
||||||
"squizlabs/php_codesniffer": "^3.7",
|
|
||||||
"tecnickcom/tcpdf": "^6.5"
|
|
||||||
},
|
|
||||||
"suggest": {
|
|
||||||
"dompdf/dompdf": "Option for rendering PDF with PDF Writer",
|
|
||||||
"ext-intl": "PHP Internationalization Functions",
|
|
||||||
"mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
|
|
||||||
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
|
|
||||||
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Maarten Balliauw",
|
|
||||||
"homepage": "https://blog.maartenballiauw.be"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Mark Baker",
|
|
||||||
"homepage": "https://markbakeruk.net"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Franck Lefevre",
|
|
||||||
"homepage": "https://rootslabs.net"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Erik Tilt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Adrien Crivelli"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
|
|
||||||
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
|
|
||||||
"keywords": [
|
|
||||||
"OpenXML",
|
|
||||||
"excel",
|
|
||||||
"gnumeric",
|
|
||||||
"ods",
|
|
||||||
"php",
|
|
||||||
"spreadsheet",
|
|
||||||
"xls",
|
|
||||||
"xlsx"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
|
|
||||||
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/2.2.2"
|
|
||||||
},
|
|
||||||
"time": "2024-08-08T02:31:26+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "psr/cache",
|
"name": "psr/cache",
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
|
@ -1668,58 +1488,6 @@
|
||||||
},
|
},
|
||||||
"time": "2019-01-08T18:20:26+00:00"
|
"time": "2019-01-08T18:20:26+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "psr/http-client",
|
|
||||||
"version": "1.0.3",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/php-fig/http-client.git",
|
|
||||||
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
|
|
||||||
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": "^7.0 || ^8.0",
|
|
||||||
"psr/http-message": "^1.0 || ^2.0"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "1.0.x-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Psr\\Http\\Client\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "PHP-FIG",
|
|
||||||
"homepage": "https://www.php-fig.org/"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Common interface for HTTP clients",
|
|
||||||
"homepage": "https://github.com/php-fig/http-client",
|
|
||||||
"keywords": [
|
|
||||||
"http",
|
|
||||||
"http-client",
|
|
||||||
"psr",
|
|
||||||
"psr-18"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"source": "https://github.com/php-fig/http-client"
|
|
||||||
},
|
|
||||||
"time": "2023-09-23T14:17:50+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "psr/http-factory",
|
"name": "psr/http-factory",
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
|
@ -1878,57 +1646,6 @@
|
||||||
},
|
},
|
||||||
"time": "2021-05-03T11:20:27+00:00"
|
"time": "2021-05-03T11:20:27+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "psr/simple-cache",
|
|
||||||
"version": "3.0.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/php-fig/simple-cache.git",
|
|
||||||
"reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865",
|
|
||||||
"reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=8.0.0"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "3.0.x-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Psr\\SimpleCache\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "PHP-FIG",
|
|
||||||
"homepage": "https://www.php-fig.org/"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Common interfaces for simple caching",
|
|
||||||
"keywords": [
|
|
||||||
"cache",
|
|
||||||
"caching",
|
|
||||||
"psr",
|
|
||||||
"psr-16",
|
|
||||||
"simple-cache"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"source": "https://github.com/php-fig/simple-cache/tree/3.0.0"
|
|
||||||
},
|
|
||||||
"time": "2021-10-29T13:26:27+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "react/cache",
|
"name": "react/cache",
|
||||||
"version": "v1.2.0",
|
"version": "v1.2.0",
|
||||||
|
|
|
@ -6,7 +6,8 @@ namespace mirzaev\arming_bot\controllers;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\controllers\core,
|
use mirzaev\arming_bot\controllers\core,
|
||||||
mirzaev\arming_bot\models\categories,
|
mirzaev\arming_bot\models\catalog as model,
|
||||||
|
mirzaev\arming_bot\models\entry,
|
||||||
mirzaev\arming_bot\models\category,
|
mirzaev\arming_bot\models\category,
|
||||||
mirzaev\arming_bot\models\product;
|
mirzaev\arming_bot\models\product;
|
||||||
|
|
||||||
|
@ -34,22 +35,18 @@ final class catalog extends core
|
||||||
*/
|
*/
|
||||||
public function index(array $parameters = []): ?string
|
public function index(array $parameters = []): ?string
|
||||||
{
|
{
|
||||||
if (!empty($parameters['categories']) && $parameters['categories'] !== ['/']) {
|
if (!empty($parameters['category'])) {
|
||||||
// Переданы категории ["category1", "category2", "category3"] (иерархия)
|
// Передана категория (идентификатор)
|
||||||
|
|
||||||
// Инициализация актуальной категории
|
// Инициализация актуальной категории
|
||||||
$category = end($parameters['categories']);
|
$category = new category(document: category::_read('d.identifier == @identifier', parameters: ['identifier' => $parameters['category']]));
|
||||||
|
|
||||||
if ($model = categories::category($category)) {
|
if ($category instanceof category) {
|
||||||
// Найдена модель обработки актуальной категории
|
// Found the category
|
||||||
|
|
||||||
if (method_exists($model, 'entries')) {
|
|
||||||
// Найден метод поиска вхождений
|
|
||||||
|
|
||||||
// Поиск категорий или товаров входящих в актуальную категорию
|
// Поиск категорий или товаров входящих в актуальную категорию
|
||||||
$entries = $model::entries(
|
$entries = entry::search(
|
||||||
category: $model->getId(),
|
document: $category,
|
||||||
filter: 'v.deleted != true && v.hidden != true',
|
|
||||||
amount: 30,
|
amount: 30,
|
||||||
errors: $this->errors['catalog']
|
errors: $this->errors['catalog']
|
||||||
);
|
);
|
||||||
|
@ -70,18 +67,11 @@ final class catalog extends core
|
||||||
// Запись товаров из буфера в глобальную переменную шаблонизатора
|
// Запись товаров из буфера в глобальную переменную шаблонизатора
|
||||||
$this->view->products = $product;
|
$this->view->products = $product;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Не переданы категории
|
// Не передана категория
|
||||||
|
|
||||||
// Поиск категорий: "categories"
|
// Поиск категорий: "categories" (самый верхний уровень)
|
||||||
// @todo сделать автоматический поиск "самой верхней" категории
|
$this->view->categories = entry::ascendants(descendant: new category, errors: $this->errors['catalog']);
|
||||||
$this->view->categories = category::_read(
|
|
||||||
filter: 'd.deleted != true && d.hidden != true',
|
|
||||||
sort: 'd.position ASC, d.name ASC, d.created DESC',
|
|
||||||
amount: 30,
|
|
||||||
errors: $this->errors['catalog']
|
|
||||||
);
|
|
||||||
|
|
||||||
// Search for products
|
// Search for products
|
||||||
/* $this->view->products = product::read(
|
/* $this->view->products = product::read(
|
||||||
|
@ -92,6 +82,11 @@ final class catalog extends core
|
||||||
); */
|
); */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generating filters
|
||||||
|
$this->view->filters = [
|
||||||
|
'brands' => product::collect('d.brand.ru', $this->errors['catalog'])
|
||||||
|
];
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||||
// GET request
|
// GET request
|
||||||
|
|
||||||
|
@ -114,7 +109,8 @@ final class catalog extends core
|
||||||
'title' => $title ?? '',
|
'title' => $title ?? '',
|
||||||
'html' => [
|
'html' => [
|
||||||
'categories' => $this->view->render('catalog/elements/categories.html'),
|
'categories' => $this->view->render('catalog/elements/categories.html'),
|
||||||
'products' => $this->view->render('catalog/elements/products/2columns.html')
|
'products' => $this->view->render('catalog/elements/products/2columns.html'),
|
||||||
|
'filters' => $this->view->render('catalog/elemments/filters.html')
|
||||||
],
|
],
|
||||||
'errors' => $this->errors
|
'errors' => $this->errors
|
||||||
]
|
]
|
||||||
|
|
|
@ -12,9 +12,6 @@ use mirzaev\arming_bot\views\templater,
|
||||||
mirzaev\arming_bot\models\settings,
|
mirzaev\arming_bot\models\settings,
|
||||||
mirzaev\arming_bot\models\suspension;
|
mirzaev\arming_bot\models\suspension;
|
||||||
|
|
||||||
// Library for ArangoDB
|
|
||||||
use ArangoDBClient\Document as _document;
|
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\controller;
|
use mirzaev\minimal\controller;
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ use mirzaev\arming_bot\controllers\core,
|
||||||
*/
|
*/
|
||||||
final class index extends core
|
final class index extends core
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the main page
|
* Render the main page
|
||||||
*
|
*
|
||||||
|
@ -23,11 +24,8 @@ final class index extends core
|
||||||
*/
|
*/
|
||||||
public function index(array $parameters = []): ?string
|
public function index(array $parameters = []): ?string
|
||||||
{
|
{
|
||||||
// Поиск товаров
|
|
||||||
/* $this->view->products = product::read(); */
|
|
||||||
|
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') return $this->view->render('catalog.html');
|
if ($_SERVER['REQUEST_METHOD'] === 'GET') return $this->view->render('index.html');
|
||||||
|
|
||||||
// Exit (fail)
|
// Exit (fail)
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -14,9 +14,6 @@ use mirzaev\arming_bot\models\core,
|
||||||
use mirzaev\arangodb\collection,
|
use mirzaev\arangodb\collection,
|
||||||
mirzaev\arangodb\document;
|
mirzaev\arangodb\document;
|
||||||
|
|
||||||
// Library для ArangoDB
|
|
||||||
use ArangoDBClient\Document as _document;
|
|
||||||
|
|
||||||
// Framework for Telegram
|
// Framework for Telegram
|
||||||
use Zanzara\Telegram\Type\User as telegram;
|
use Zanzara\Telegram\Type\User as telegram;
|
||||||
|
|
||||||
|
@ -24,9 +21,11 @@ use Zanzara\Telegram\Type\User as telegram;
|
||||||
use exception;
|
use exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model of an account
|
* Model of account
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\arming_bot\models
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
*/
|
*/
|
||||||
final class account extends core implements arangodb_document_interface
|
final class account extends core implements arangodb_document_interface
|
||||||
|
@ -39,40 +38,47 @@ final class account extends core implements arangodb_document_interface
|
||||||
final public const string COLLECTION = 'account';
|
final public const string COLLECTION = 'account';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Инициализация
|
* Initialize
|
||||||
*
|
*
|
||||||
* @param int $id Идентификатор Telegram
|
* @param int $identifier Identifier of the account
|
||||||
* @param telegram|array|null $registration Данные для регистрация, если аккаунт не найден
|
* @param telegram|array|null $registration Данные для регистрация, если аккаунт не найден
|
||||||
* @param array &$errors Registry of errors
|
* @param array &$errors Registry of errors
|
||||||
*
|
*
|
||||||
* @return static|null Объект аккаунта, если найден
|
* @return static|null Объект аккаунта, если найден
|
||||||
*/
|
*/
|
||||||
public static function initialization(int $id, telegram|array|null $registration = null, array &$errors = []): static|null
|
public static function initialize(int $identifier, telegram|array|null $registration = null, array &$errors = []): static|null
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (collection::init(core::$arangodb->session, self::COLLECTION)) {
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
if ($document = collection::search(core::$arangodb->session, sprintf("FOR d IN %s FILTER d.id == %u RETURN d", self::COLLECTION, $id))) {
|
// Initialized the collection
|
||||||
// Найден аккаунт
|
|
||||||
|
|
||||||
// Инициализация объекта аккаунта
|
try {
|
||||||
$account = new static;
|
// Initializing the account and exit (success)
|
||||||
|
return new static(
|
||||||
|
document: collection::execute(
|
||||||
|
<<<'AQL'
|
||||||
|
FOR d IN @@collection
|
||||||
|
FILTER d.identifier == @identifier
|
||||||
|
RETURN d
|
||||||
|
AQL,
|
||||||
|
[
|
||||||
|
'@collection' => static::COLLECTION,
|
||||||
|
'identifier' => $identifier
|
||||||
|
],
|
||||||
|
errors: $errors
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (exception $e) {
|
||||||
|
if ($registration) {
|
||||||
|
// Not found the account and registration is requested
|
||||||
|
|
||||||
// Запись инстанции документа в объект
|
// Creating account
|
||||||
$account->document = $document;
|
$account = document::write(
|
||||||
|
static::COLLECTION,
|
||||||
// Возврат (успех)
|
|
||||||
return $account;
|
|
||||||
} else if ($registration) {
|
|
||||||
// Не найден аккаунт и запрошена его регистрация
|
|
||||||
|
|
||||||
// Создание аккаунта
|
|
||||||
document::write(
|
|
||||||
core::$arangodb->session,
|
|
||||||
self::COLLECTION,
|
|
||||||
(is_array($registration)
|
(is_array($registration)
|
||||||
? $registration :
|
? $registration :
|
||||||
[
|
[
|
||||||
'id' => $registration->getId(),
|
'identifier' => $registration->getId(),
|
||||||
'name' => [
|
'name' => [
|
||||||
'first' => $registration->getFirstName(),
|
'first' => $registration->getFirstName(),
|
||||||
'last' => $registration->getLastName()
|
'last' => $registration->getLastName()
|
||||||
|
@ -101,15 +107,21 @@ final class account extends core implements arangodb_document_interface
|
||||||
]) + [
|
]) + [
|
||||||
'version' => ROBOT_VERSION,
|
'version' => ROBOT_VERSION,
|
||||||
'active' => true
|
'active' => true
|
||||||
]
|
],
|
||||||
|
errors: $errors
|
||||||
);
|
);
|
||||||
|
|
||||||
// Инициализация (без регистрации)
|
if ($account) {
|
||||||
return static::initialization($id, errors: $errors);
|
// Created account
|
||||||
} else throw new exception('Account not found');
|
|
||||||
} else throw new exception('Failed to initialize document collection: ' . self::COLLECTION);
|
// 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) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
@ -118,7 +130,7 @@ final class account extends core implements arangodb_document_interface
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Выход (провал)
|
// Exit (fail)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,487 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace mirzaev\arming_bot\models;
|
||||||
|
|
||||||
|
// Files of the project
|
||||||
|
use mirzaev\arming_bot\models\core,
|
||||||
|
mirzaev\arming_bot\models\product,
|
||||||
|
mirzaev\arming_bot\models\category,
|
||||||
|
mirzaev\arming_bot\models\entry,
|
||||||
|
mirzaev\arming_bot\models\traits\files,
|
||||||
|
mirzaev\arming_bot\models\traits\yandex\disk as yandex;
|
||||||
|
|
||||||
|
// Framework for ArangoDB
|
||||||
|
use mirzaev\arangodb\collection,
|
||||||
|
mirzaev\arangodb\document;
|
||||||
|
|
||||||
|
// Framework for Excel
|
||||||
|
use avadim\FastExcelReader\Excel as excel;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model of the catalog
|
||||||
|
*
|
||||||
|
* @package mirzaev\arming_bot\models
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class catalog extends core
|
||||||
|
{
|
||||||
|
use yandex, files {
|
||||||
|
yandex::download as yandex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @todo
|
||||||
|
* 1. Сначала создать все категории и затем снова по циклу пройтись уже создавать entry между ними
|
||||||
|
* 2. Сжимать изображения
|
||||||
|
*/
|
||||||
|
public static function import(
|
||||||
|
string $document,
|
||||||
|
int &$categories_loaded = 0,
|
||||||
|
int &$categories_created = 0,
|
||||||
|
int &$categories_updated = 0,
|
||||||
|
int &$categories_deleted = 0,
|
||||||
|
int &$categories_old = 0,
|
||||||
|
int &$categories_new = 0,
|
||||||
|
int &$products_loaded = 0,
|
||||||
|
int &$products_created = 0,
|
||||||
|
int &$products_updated = 0,
|
||||||
|
int &$products_deleted = 0,
|
||||||
|
int &$products_old = 0,
|
||||||
|
int &$products_new = 0,
|
||||||
|
string $language = 'en',
|
||||||
|
array &$errors = []
|
||||||
|
): void {
|
||||||
|
try {
|
||||||
|
// Initializing the spreadsheet
|
||||||
|
$spreadsheet = excel::open($document);
|
||||||
|
|
||||||
|
// Inititalizing worksheets
|
||||||
|
$categories = $spreadsheet->getSheet('Категории');
|
||||||
|
$products = $spreadsheet->getSheet('Товары');
|
||||||
|
|
||||||
|
// Counting old documents
|
||||||
|
$categories_old = collection::count(category::COLLECTION, errors: $errors);
|
||||||
|
$products_old = collection::count(product::COLLECTION, errors: $errors);
|
||||||
|
|
||||||
|
// Initializing the buffer of handler categories and products
|
||||||
|
$handled = [
|
||||||
|
'categories' => [],
|
||||||
|
'products' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach (
|
||||||
|
$categories->nextRow(
|
||||||
|
[
|
||||||
|
'A' => 'identifier',
|
||||||
|
'B' => 'name',
|
||||||
|
'C' => 'category',
|
||||||
|
'D' => 'images',
|
||||||
|
'E' => 'position'
|
||||||
|
],
|
||||||
|
excel::KEYS_FIRST_ROW
|
||||||
|
) as $number => $row
|
||||||
|
) {
|
||||||
|
// Iterate over categories
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!empty($row['identifier']) && !empty($row['name'])) {
|
||||||
|
// All required cells are filled in
|
||||||
|
|
||||||
|
// Incrementing the counter of loaded categories
|
||||||
|
++$categories_loaded;
|
||||||
|
|
||||||
|
// Declaring the variable with the status that a new category has been created
|
||||||
|
$created = false;
|
||||||
|
|
||||||
|
// 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 name of the category
|
||||||
|
$category->name[$language] === $row['name'] || $category->name = [[$language => $row['name']]] + $category->name ?? [];
|
||||||
|
|
||||||
|
// Initializing position of the category
|
||||||
|
$category->position === $row['position'] || $category->position = $row['position'];
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Not found the category
|
||||||
|
|
||||||
|
// Creating the category
|
||||||
|
$_id = category::write((int) $row['identifier'], [$language => $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);
|
||||||
|
|
||||||
|
// Incrementing the counter of created categories
|
||||||
|
if ($created) ++$categories_created;
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($category instanceof category) {
|
||||||
|
// Found 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);
|
||||||
|
|
||||||
|
if ($ascendant instanceof category) {
|
||||||
|
// Found the ascendant category
|
||||||
|
|
||||||
|
// Deleting entries of the category in ArangoDB
|
||||||
|
entry::banish($category, $errors);
|
||||||
|
|
||||||
|
// Writing the category as an entry to the ascendant category in ArangoDB
|
||||||
|
entry::write($category, $ascendant, $errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($row['images'])) {
|
||||||
|
// Received images
|
||||||
|
|
||||||
|
// Initializing new images of the category
|
||||||
|
$images = explode(' ', trim($row['images']));
|
||||||
|
|
||||||
|
// Reinitialize images? (true, if no images found or their amount does not match)
|
||||||
|
$reinitialize = !$category->images || count($category->images) !== count($images);
|
||||||
|
|
||||||
|
// Checking the identity of existing images with new images (if reinitialization of images has not yet been requested)
|
||||||
|
if (!$reinitialize) foreach ($category->images as $key => $image) if ($reinitialize = $image['source'] !== $images[$key]) break;
|
||||||
|
|
||||||
|
if ($reinitialize) {
|
||||||
|
// Requested reinitialization of images
|
||||||
|
|
||||||
|
// Initializing the buffer of images
|
||||||
|
$buffer = [];
|
||||||
|
|
||||||
|
foreach ($images as $index => $image) {
|
||||||
|
// Iterating over new images
|
||||||
|
|
||||||
|
// Skipping empty URI`s
|
||||||
|
if (empty($image = trim($image))) continue;
|
||||||
|
|
||||||
|
// Initializing path to directory of the image in storage
|
||||||
|
$directory = DIRECTORY_SEPARATOR . 'categories' . DIRECTORY_SEPARATOR . $row['identifier'];
|
||||||
|
|
||||||
|
// Initializing URL of the image in storage
|
||||||
|
$url = STORAGE . $directory;
|
||||||
|
|
||||||
|
// Initializing URN of the image in storage
|
||||||
|
$urn = $index . '.jpg';
|
||||||
|
|
||||||
|
// Initializing URI of the image in storage
|
||||||
|
$uri = $url . DIRECTORY_SEPARATOR . $urn;
|
||||||
|
|
||||||
|
// Initializing the directory in storage
|
||||||
|
if (!file_exists($url)) mkdir($url, 0775, true);
|
||||||
|
|
||||||
|
if (static::yandex($image, $uri, errors: $errors)) {
|
||||||
|
// The image is downloaded
|
||||||
|
|
||||||
|
// Writing the image to the buffer if images
|
||||||
|
$buffer[] = [
|
||||||
|
'source' => $image,
|
||||||
|
'storage' => $directory . DIRECTORY_SEPARATOR . $urn
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializing images of the category
|
||||||
|
$category->images = $buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writing in ArangoDB
|
||||||
|
$updated = document::update($category->__document(), errors: $errors);
|
||||||
|
|
||||||
|
// Incrementing the counter of updated categories
|
||||||
|
if ($updated && !$created) ++$categories_updated;
|
||||||
|
} else throw new exception("Failed to initialize category: {$row['name']} ($number)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writing to the registry of handled categories and products
|
||||||
|
$handled['categories'][] = $row['identifier'];
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (
|
||||||
|
$products->nextRow(
|
||||||
|
[
|
||||||
|
'A' => 'identifier',
|
||||||
|
'B' => 'name',
|
||||||
|
'C' => 'category',
|
||||||
|
'D' => 'description',
|
||||||
|
'E' => 'cost',
|
||||||
|
'F' => 'weight',
|
||||||
|
'G' => 'x',
|
||||||
|
'H' => 'y',
|
||||||
|
'I' => 'z',
|
||||||
|
'J' => 'brand',
|
||||||
|
'K' => 'compatibility',
|
||||||
|
'L' => 'images',
|
||||||
|
'M' => 'position'
|
||||||
|
],
|
||||||
|
excel::KEYS_FIRST_ROW
|
||||||
|
) as $number => $row
|
||||||
|
) {
|
||||||
|
// Iterate over products
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!empty($row['identifier']) && !empty($row['name'])) {
|
||||||
|
// All required cells are filled in
|
||||||
|
|
||||||
|
// Incrementing the counter of loaded products
|
||||||
|
++$products_loaded;
|
||||||
|
|
||||||
|
// Declaring the variable with the status that a new product has been created
|
||||||
|
$created = false;
|
||||||
|
|
||||||
|
// 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 name of the category
|
||||||
|
$product->name[$language] === $row['name'] || $product->name = [[$language => $row['name']]] + $product->name ?? [];
|
||||||
|
|
||||||
|
// Initializing position of the product
|
||||||
|
$product->position === $row['position'] || $product->position = $row['position'];
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Not found the product
|
||||||
|
|
||||||
|
// Creating the product
|
||||||
|
$_id = product::write(
|
||||||
|
(int) $row['identifier'],
|
||||||
|
[$language => $row['name']],
|
||||||
|
[$language => $row['description']],
|
||||||
|
(float) $row['cost'],
|
||||||
|
(float) $row['weight'],
|
||||||
|
['x' => $row['x'], 'y' => $row['y'], 'z' => $row['z']],
|
||||||
|
$row['position'] ?? null,
|
||||||
|
errors: $errors
|
||||||
|
);
|
||||||
|
|
||||||
|
// Initializing the product
|
||||||
|
$product = new product(document: $created = product::_read(sprintf('d._id == "%s"', $_id), errors: $errors)[0] ?? null);
|
||||||
|
|
||||||
|
// Incrementing the counter of created products
|
||||||
|
if ($created) ++$products_created;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($product instanceof product) {
|
||||||
|
// Found 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);
|
||||||
|
|
||||||
|
if ($category instanceof category) {
|
||||||
|
// Found the ascendant category
|
||||||
|
|
||||||
|
// Deleting entries of the product in ArangoDB
|
||||||
|
entry::banish($product, $errors);
|
||||||
|
|
||||||
|
// Writing the product as an entry to the ascendant category in ArangoDB
|
||||||
|
entry::write($product, $category, $errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($row['images'])) {
|
||||||
|
// Received images
|
||||||
|
|
||||||
|
// Initializing new images of the category
|
||||||
|
$images = explode(' ', trim($row['images']));
|
||||||
|
|
||||||
|
// Reinitialize images? (true, if no images found or their amount does not match)
|
||||||
|
$reinitialize = !$product->images || count($product->images) !== count($images);
|
||||||
|
|
||||||
|
// Checking the identity of existing images with new images (if reinitialization of images has not yet been requested)
|
||||||
|
if (!$reinitialize) foreach ($product->images as $key => $image) if ($reinitialize = $image['source'] !== $images[$key]) break;
|
||||||
|
|
||||||
|
if ($reinitialize) {
|
||||||
|
// Requested reinitialization of images
|
||||||
|
|
||||||
|
// Initializing the buffer of images
|
||||||
|
$buffer = [];
|
||||||
|
|
||||||
|
foreach ($images as $index => $image) {
|
||||||
|
// Iterating over new images
|
||||||
|
|
||||||
|
// Skipping empty URI`s
|
||||||
|
if (empty($image = trim($image))) continue;
|
||||||
|
|
||||||
|
// Initializing path to directory of the image in storage
|
||||||
|
$directory = DIRECTORY_SEPARATOR . 'products' . DIRECTORY_SEPARATOR . $row['identifier'];
|
||||||
|
|
||||||
|
// Initializing URL of the image in storage
|
||||||
|
$url = STORAGE . $directory;
|
||||||
|
|
||||||
|
// Initializing URN of the image in storage
|
||||||
|
$urn = $index . '.jpg';
|
||||||
|
|
||||||
|
// Initializing URI of the image in storage
|
||||||
|
$uri = $url . DIRECTORY_SEPARATOR . $urn;
|
||||||
|
|
||||||
|
// Initializing the directory in storage
|
||||||
|
if (!file_exists($url)) mkdir($url, 0775, true);
|
||||||
|
|
||||||
|
if (static::yandex($image, $uri, errors: $errors)) {
|
||||||
|
// The image is downloaded
|
||||||
|
|
||||||
|
// Writing the image to the buffer if images
|
||||||
|
$buffer[] = [
|
||||||
|
'source' => $image,
|
||||||
|
'storage' => $directory . DIRECTORY_SEPARATOR . $urn
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializing images of the category
|
||||||
|
$product->images = $buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writing in ArangoDB
|
||||||
|
$updated = document::update($product->__document(), errors: $errors);
|
||||||
|
|
||||||
|
// Incrementing the counter of updated categories
|
||||||
|
if ($updated && !$created) ++$products_updated;
|
||||||
|
} else throw new exception("Failed to initialize product: {$row['name']} ($number)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writing to the registry of handled categories and products
|
||||||
|
$handled['products'][] = $row['identifier'];
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deleting old categories
|
||||||
|
foreach (
|
||||||
|
category::_read(
|
||||||
|
/* filter: sprintf('%s - d.updated > 3600', time()), */
|
||||||
|
sort: 'd.updated DESC',
|
||||||
|
amount: 100000,
|
||||||
|
errors: $errors
|
||||||
|
) as $document
|
||||||
|
) {
|
||||||
|
// Iterating over categories
|
||||||
|
|
||||||
|
// Initializing the category
|
||||||
|
$category = new category(document: $document);
|
||||||
|
|
||||||
|
if (
|
||||||
|
$category instanceof category
|
||||||
|
&& array_search($category->identifier, $handled['categories']) === false
|
||||||
|
) {
|
||||||
|
// Not found identifier of the product in the buffer of handled categories and products
|
||||||
|
|
||||||
|
// Deleting images of the category from storage
|
||||||
|
static::delete(STORAGE . DIRECTORY_SEPARATOR . 'categories' . DIRECTORY_SEPARATOR . $category->identifier, errors: $errors);
|
||||||
|
|
||||||
|
// Deleting entries of the category in ArangoDB
|
||||||
|
entry::banish($category, errors: $errors);
|
||||||
|
|
||||||
|
// Deleting the category in ArangoDB
|
||||||
|
document::delete($category->__document(), errors: $errors);
|
||||||
|
|
||||||
|
// Incrementing the counter of deleted categories
|
||||||
|
++$categories_deleted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deleting old products
|
||||||
|
foreach (
|
||||||
|
product::_read(
|
||||||
|
/* filter: sprintf('%s - d.updated > 3600', time()), */
|
||||||
|
sort: 'd.updated DESC',
|
||||||
|
amount: 100000,
|
||||||
|
errors: $errors
|
||||||
|
) as $document
|
||||||
|
) {
|
||||||
|
// Iterating over products
|
||||||
|
|
||||||
|
// Initializing the category
|
||||||
|
$product = new product(document: $document);
|
||||||
|
|
||||||
|
if (
|
||||||
|
$product instanceof product
|
||||||
|
&& array_search($product->identifier, $handled['products']) === false
|
||||||
|
) {
|
||||||
|
// Not found identifier of the product in the buffer of handled categories and products
|
||||||
|
|
||||||
|
// Deleting images of the product from storage
|
||||||
|
static::delete(STORAGE . DIRECTORY_SEPARATOR . 'products' . DIRECTORY_SEPARATOR . $product->identifier, errors: $errors);
|
||||||
|
|
||||||
|
// Deleting entries of the product in ArangoDB
|
||||||
|
entry::banish($product, errors: $errors);
|
||||||
|
|
||||||
|
// Deleting the product in ArangoDB
|
||||||
|
document::delete($product->__document(), errors: $errors);
|
||||||
|
|
||||||
|
// Incrementing the counter of deleted products
|
||||||
|
++$products_deleted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Counting new documents
|
||||||
|
$categories_new = collection::count(category::COLLECTION, errors: $errors);
|
||||||
|
$products_new = collection::count(product::COLLECTION, errors: $errors);
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,294 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Framework for ArangoDB
|
|
||||||
use mirzaev\arangodb\collection,
|
|
||||||
mirzaev\arangodb\document;
|
|
||||||
|
|
||||||
// Library для ArangoDB
|
|
||||||
use ArangoDBClient\Document as _document;
|
|
||||||
|
|
||||||
// Built-in libraries
|
|
||||||
use exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Model of a category
|
|
||||||
*
|
|
||||||
* @package mirzaev\arming_bot\models
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
class categories extends core implements arangodb_document_interface
|
|
||||||
{
|
|
||||||
use arangodb_document_trait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of the collection in ArangoDB
|
|
||||||
*/
|
|
||||||
public const string COLLECTION = 'THIS_COLLECTION_SHOULD_NOT_EXIST';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Запись категории
|
|
||||||
*
|
|
||||||
* @param string $name Название
|
|
||||||
* @param arrau $labels Ярлыки для отображения в интерфейсе ['EN' => "Label"]
|
|
||||||
* @param array $hierarchy Иерархия вложенности (от родителей к потомкам: [ model, model ... ])
|
|
||||||
* @param array &$errors Registry of errors
|
|
||||||
*
|
|
||||||
* @return string|null Идентификатор (_id) документа, если создан
|
|
||||||
*/
|
|
||||||
public static function write(
|
|
||||||
string $name,
|
|
||||||
array $labels = ['RU' => 'Без названия'],
|
|
||||||
array $hierarchy = [],
|
|
||||||
array &$errors = []
|
|
||||||
): string|null {
|
|
||||||
try {
|
|
||||||
if (collection::init(core::$arangodb->session, static::COLLECTION)) {
|
|
||||||
// Инициализирована коллекция
|
|
||||||
|
|
||||||
// Создание категории
|
|
||||||
$category = document::write(
|
|
||||||
core::$arangodb->session,
|
|
||||||
static::COLLECTION,
|
|
||||||
[
|
|
||||||
'name' => $name,
|
|
||||||
'labels' => $labels,
|
|
||||||
'version' => ROBOT_VERSION
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($category) {
|
|
||||||
// Создана категория
|
|
||||||
|
|
||||||
/* if (collection::init(core::$arangodb->session, 'entry', true)) {
|
|
||||||
// Инициализирована коллекция
|
|
||||||
|
|
||||||
foreach ($hierarchy as $model) {
|
|
||||||
// Перебор иерархической структуры категорий
|
|
||||||
|
|
||||||
// Инициализация вложенной категории (следующей в массиве)
|
|
||||||
$next = current($hierarchy);
|
|
||||||
|
|
||||||
// Поиск ребра описывающего иерархическую связь
|
|
||||||
|
|
||||||
document::write(core::$arangodb->session, 'entry');
|
|
||||||
}
|
|
||||||
} else throw new exception('Failed to initialize document collection: ' . static::COLLECTION); */
|
|
||||||
}
|
|
||||||
} else throw new exception('Failed to initialize edge collection: entry');
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Write to the registry of errors
|
|
||||||
$errors[] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Выход (провал)
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Поиск вхождений (подкатегории или товары)
|
|
||||||
*
|
|
||||||
* Находит вхождения через ребро entry
|
|
||||||
* Генерирует _type со значениями "category" и "product"
|
|
||||||
* относительно того есть ли у документа ещё вложения (у product вложений быть не может)
|
|
||||||
* Объединяет возвращаемые объекты документа с переменной _type
|
|
||||||
*
|
|
||||||
* @param string|null $category Category identifier (_id)
|
|
||||||
* @param string|null $filter Expression for filtering (AQL)
|
|
||||||
* @param string|null $sort Expression for sorting (AQL)
|
|
||||||
* @param int $page Страница
|
|
||||||
* @param int $amount Количество товаров на странице
|
|
||||||
* @param array &$errors Registry of errors
|
|
||||||
*
|
|
||||||
* @return array Массив с найденными вхождениями (может быть пустым)
|
|
||||||
*/
|
|
||||||
public static function entries(
|
|
||||||
?string $category = null,
|
|
||||||
?string $filter = null,
|
|
||||||
?string $sort = 'v.promotion DESC, v.position ASC, v.created DESC',
|
|
||||||
int $page = 1,
|
|
||||||
int $amount = 100,
|
|
||||||
array &$errors = []
|
|
||||||
): array {
|
|
||||||
try {
|
|
||||||
if (collection::init(core::$arangodb->session, static::COLLECTION)) {
|
|
||||||
// Инициализирована коллекция
|
|
||||||
|
|
||||||
if ($documents = collection::search(
|
|
||||||
core::$arangodb->session,
|
|
||||||
sprintf(
|
|
||||||
<<<AQL
|
|
||||||
FOR v IN 1..1 INBOUND %s GRAPH hierarchy
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
LIMIT %u, %u
|
|
||||||
LET _type = (FOR v2 IN INBOUND v._id GRAPH hierarchy RETURN v2)[0] ? "category" : "product"
|
|
||||||
RETURN MERGE(v, {_type})
|
|
||||||
AQL,
|
|
||||||
empty($category) ? '(FOR d IN ' . ${static::COLLECTION} . 'LIMIT 1 RETURN d._id)[0]' : "\"$category\"",
|
|
||||||
empty($filter) ? '' : "FILTER $filter",
|
|
||||||
empty($sort) ? '' : "SORT $sort",
|
|
||||||
--$page <= 0 ? $page = 0 : $page * $amount,
|
|
||||||
$amount,
|
|
||||||
)
|
|
||||||
)) {
|
|
||||||
// Найдены вхождения
|
|
||||||
|
|
||||||
// Возврат (успех)
|
|
||||||
return is_array($documents) ? $documents : [$documents];
|
|
||||||
} else return [];
|
|
||||||
} else throw new exception('Failed to initialize document collection: ' . static::COLLECTION);
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Write to the registry of errors
|
|
||||||
$errors[] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Выход (провал)
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Поиск категорий и товаров
|
|
||||||
*
|
|
||||||
* Ищет категории и товары по коллекции рёбер entry из _from и _to
|
|
||||||
*
|
|
||||||
* @param array &$errors Registry of errors
|
|
||||||
*
|
|
||||||
* @return array Массив с уникализированными найденными коллекциями (может быть пустым)
|
|
||||||
*/
|
|
||||||
protected static function collections(
|
|
||||||
array &$errors = []
|
|
||||||
): array {
|
|
||||||
try {
|
|
||||||
if (collection::init(core::$arangodb->session, $collection = 'entry')) {
|
|
||||||
// Инициализирована коллекция
|
|
||||||
|
|
||||||
if ($names = collection::search(
|
|
||||||
core::$arangodb->session,
|
|
||||||
sprintf(
|
|
||||||
<<<AQL
|
|
||||||
FOR e IN %s
|
|
||||||
COLLECT AGGREGATE
|
|
||||||
from_category = UNIQUE(PARSE_IDENTIFIER(e._from).collection),
|
|
||||||
to_category = UNIQUE(PARSE_IDENTIFIER(e._to).collection)
|
|
||||||
RETURN UNIQUE(UNION(from_category, to_category))
|
|
||||||
AQL,
|
|
||||||
$collection
|
|
||||||
)
|
|
||||||
)) {
|
|
||||||
// Найдены коллекции
|
|
||||||
|
|
||||||
// Возврат (успех)
|
|
||||||
return $names->getAll();
|
|
||||||
} else return [];
|
|
||||||
} else throw new exception('Failed to initialize edge collection: entry');
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Write to the registry of errors
|
|
||||||
$errors[] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Выход (провал)
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Поиск категории по названияю
|
|
||||||
*
|
|
||||||
* Перебирает все коллекции из self::collections() и ищет в них соответствие с параметром name
|
|
||||||
* ВНИМАНИЕ: НЕЛЬЗЯ ДОПУСКАТЬ ОДИНАКОВЫЕ НАЗВАНИЯ СРЕДИ РАЗНЫХ КАТЕГОРИЙ
|
|
||||||
*
|
|
||||||
* @param string $name Name of a collection
|
|
||||||
* @param array &$errors Registry of errors
|
|
||||||
*
|
|
||||||
* @return categories|null Модель имплементирующая документ с категорией, если была найдена
|
|
||||||
*/
|
|
||||||
public static function category(
|
|
||||||
string $name,
|
|
||||||
array &$errors = []
|
|
||||||
): ?categories {
|
|
||||||
try {
|
|
||||||
// Инициалиация списка коллекций
|
|
||||||
$collections = self::collections($errors);
|
|
||||||
|
|
||||||
if (count($collections) > 0) {
|
|
||||||
// Найдены коллекции
|
|
||||||
|
|
||||||
// Инициализация буфера части запроса со списком коллекций для аргументов UNION()
|
|
||||||
$union = [];
|
|
||||||
foreach ($collections as $collection) $union[] = "FOR d IN $collection RETURN d";
|
|
||||||
unset($collection);
|
|
||||||
|
|
||||||
if ($document = collection::search(
|
|
||||||
core::$arangodb->session,
|
|
||||||
sprintf(
|
|
||||||
<<<AQL
|
|
||||||
FOR u IN UNION(%s)
|
|
||||||
FILTER u.name == "%s"
|
|
||||||
SORT u.created ASC
|
|
||||||
LIMIT 1
|
|
||||||
RETURN u
|
|
||||||
AQL,
|
|
||||||
implode(', ', $union),
|
|
||||||
$name
|
|
||||||
)
|
|
||||||
)) {
|
|
||||||
// Найдена категория
|
|
||||||
|
|
||||||
// Инициализация названия коллекции
|
|
||||||
$collection = explode('/', $document->getId())[0];
|
|
||||||
|
|
||||||
if (class_exists($model = "mirzaev\\arming_bot\\models\\$collection")) {
|
|
||||||
// Найдена модель имплементирующая документы из этой коллекции
|
|
||||||
|
|
||||||
// Инициализация объекта модели
|
|
||||||
$object = new $model;
|
|
||||||
|
|
||||||
if ($object instanceof categories) {
|
|
||||||
// Объект является инстанцией категории (то есть не товара)
|
|
||||||
|
|
||||||
// Запись инстанции документа в объект модели
|
|
||||||
$object->document = $document;
|
|
||||||
|
|
||||||
// Возврат (успех)
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else return null;
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Write to the registry of errors
|
|
||||||
$errors[] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Выход (провал)
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,18 +5,81 @@ declare(strict_types=1);
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\arming_bot\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\categories;
|
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;
|
||||||
|
|
||||||
|
// Framework for ArangoDB
|
||||||
|
use mirzaev\arangodb\collection,
|
||||||
|
mirzaev\arangodb\document;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use exception;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model of a category
|
* Model of category
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\arming_bot\models
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
*/
|
*/
|
||||||
final class category extends categories
|
final class category extends core implements arangodb_document_interface
|
||||||
{
|
{
|
||||||
|
use arangodb_document_trait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the collection in ArangoDB
|
* Name of the collection in ArangoDB
|
||||||
*/
|
*/
|
||||||
final public const string COLLECTION = 'category';
|
final public const string COLLECTION = 'category';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the category
|
||||||
|
*
|
||||||
|
* @param int $identifier Identifier (unique)
|
||||||
|
* @param array $name Name [['en' => value], ['ru' => значение]]
|
||||||
|
* @param int|null $position Position for soring in the catalog (ASC)
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return string|null Identifier (_id) of the document in ArangoDB, if created
|
||||||
|
*
|
||||||
|
* @todo
|
||||||
|
* 1. Bind parameters
|
||||||
|
*/
|
||||||
|
public static function write(
|
||||||
|
int $identifier,
|
||||||
|
array $name = [['en' => 'ERROR']],
|
||||||
|
?int $position = null,
|
||||||
|
array &$errors = []
|
||||||
|
): string|null {
|
||||||
|
try {
|
||||||
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
|
// Initialized the collection
|
||||||
|
|
||||||
|
// Writing to ArangoDB and exit (success)
|
||||||
|
return document::write(
|
||||||
|
static::COLLECTION,
|
||||||
|
[
|
||||||
|
'identifier' => $identifier,
|
||||||
|
'name' => $name,
|
||||||
|
'position' => $position,
|
||||||
|
'version' => ROBOT_VERSION
|
||||||
|
],
|
||||||
|
errors: $errors
|
||||||
|
);
|
||||||
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Framework for ArangoDB
|
||||||
|
use mirzaev\arangodb\enumerations\collection\type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model of connect
|
||||||
|
*
|
||||||
|
* @package mirzaev\arming_bot\models
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class connect extends core implements arangodb_document_interface
|
||||||
|
{
|
||||||
|
use arangodb_document_trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the collection in ArangoDB
|
||||||
|
*/
|
||||||
|
final public const string COLLECTION = 'connect';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of the collection in ArangoDB
|
||||||
|
*/
|
||||||
|
public const type TYPE = type::edge;
|
||||||
|
}
|
|
@ -10,11 +10,10 @@ use mirzaev\minimal\model;
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\connection as arangodb,
|
use mirzaev\arangodb\connection as arangodb,
|
||||||
mirzaev\arangodb\collection,
|
mirzaev\arangodb\collection,
|
||||||
mirzaev\arangodb\document;
|
mirzaev\arangodb\enumerations\collection\type;
|
||||||
|
|
||||||
// Libraries for ArangoDB
|
// Libraries for ArangoDB
|
||||||
use ArangoDBClient\Document as _document,
|
use ArangoDBClient\Document as _document;
|
||||||
ArangoDBClient\DocumentHandler as _document_handler;
|
|
||||||
|
|
||||||
// Built-in libraries
|
// Built-in libraries
|
||||||
use exception;
|
use exception;
|
||||||
|
@ -23,6 +22,8 @@ use exception;
|
||||||
* Core of models
|
* Core of models
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\arming_bot\models
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
*/
|
*/
|
||||||
class core extends model
|
class core extends model
|
||||||
|
@ -47,6 +48,11 @@ class core extends model
|
||||||
*/
|
*/
|
||||||
public const string COLLECTION = 'THIS_COLLECTION_SHOULD_NOT_EXIST';
|
public const string COLLECTION = 'THIS_COLLECTION_SHOULD_NOT_EXIST';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of the collection in ArangoDB
|
||||||
|
*/
|
||||||
|
public const type TYPE = type::document;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor of an instance
|
* Constructor of an instance
|
||||||
*
|
*
|
||||||
|
@ -66,7 +72,7 @@ class core extends model
|
||||||
if (isset($arangodb)) {
|
if (isset($arangodb)) {
|
||||||
// Recieved an instance of a session of ArangoDB
|
// Recieved an instance of a session of ArangoDB
|
||||||
|
|
||||||
// Write an instance of a session of ArangoDB to the property
|
// Writing an instance of a session of ArangoDB to the property
|
||||||
$this->__set('arangodb', $arangodb);
|
$this->__set('arangodb', $arangodb);
|
||||||
} else {
|
} else {
|
||||||
// Not recieved an instance of a session of ArangoDB
|
// Not recieved an instance of a session of ArangoDB
|
||||||
|
@ -78,14 +84,15 @@ class core extends model
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read from ArangoDB
|
* Read document from ArangoDB
|
||||||
*
|
*
|
||||||
* @param string $filter Expression for filtering (AQL)
|
* @param string $filter Expression for filtering (AQL)
|
||||||
* @param string $sort Expression for sorting (AQL)
|
* @param string $sort Expression for sorting (AQL)
|
||||||
* @param int $amount Amount of documents for collect
|
* @param int $amount Amount of documents for collect
|
||||||
* @param int $page Page
|
* @param int $page Page
|
||||||
* @param string $return Expression describing the parameters to return (AQL)
|
* @param string $return Expression describing the parameters to return (AQL)
|
||||||
* @param array &$errors The registry on errors
|
* @param array $parameters Binded parameters for placeholders ['placeholder' => parameter]
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
*
|
*
|
||||||
* @return mixed An array of instances of documents from ArangoDB, if they are found
|
* @return mixed An array of instances of documents from ArangoDB, if they are found
|
||||||
*/
|
*/
|
||||||
|
@ -95,37 +102,40 @@ class core extends model
|
||||||
int $amount = 1,
|
int $amount = 1,
|
||||||
int $page = 1,
|
int $page = 1,
|
||||||
string $return = 'd',
|
string $return = 'd',
|
||||||
|
array $parameters = [],
|
||||||
array &$errors = []
|
array &$errors = []
|
||||||
): _document|array|null {
|
): _document|array|null {
|
||||||
try {
|
try {
|
||||||
if (collection::init(static::$arangodb->session, static::COLLECTION)) {
|
if (collection::initialize(static::COLLECTION, static::TYPE)) {
|
||||||
// Initialized the collection
|
// Initialized the collection
|
||||||
|
|
||||||
// Read from ArangoDB and exit (success)
|
// Read from ArangoDB
|
||||||
$result = collection::search(
|
$result = collection::execute(
|
||||||
static::$arangodb->session,
|
|
||||||
sprintf(
|
sprintf(
|
||||||
<<<'AQL'
|
<<<'AQL'
|
||||||
FOR d IN %s
|
FOR d IN @@collection
|
||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
LIMIT %d, %d
|
LIMIT @offset, @amount
|
||||||
RETURN %s
|
RETURN @return
|
||||||
AQL,
|
AQL,
|
||||||
static::COLLECTION,
|
|
||||||
empty($filter) ? '' : "FILTER $filter",
|
empty($filter) ? '' : "FILTER $filter",
|
||||||
empty($sort) ? '' : "SORT $sort",
|
empty($sort) ? '' : "SORT $sort",
|
||||||
--$page <= 0 ? 0 : $page * $amount,
|
),
|
||||||
$amount,
|
[
|
||||||
$return
|
'@collection' => static::COLLECTION,
|
||||||
)
|
'offset' => --$page <= 0 ? 0 : $page * $amount,
|
||||||
|
'amount' => $amount,
|
||||||
|
'return' => $return
|
||||||
|
] + $parameters,
|
||||||
|
errors: $errors
|
||||||
);
|
);
|
||||||
|
|
||||||
// Выход (успех)
|
// Exit (success)
|
||||||
return is_array($result) ? $result : [$result];
|
return is_array($result) ? $result : [$result];
|
||||||
} else throw new exception('Failed to initialize the collection');
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
@ -138,50 +148,6 @@ class core extends model
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update in ArangoDB
|
|
||||||
*
|
|
||||||
* @param _document $instance Instance of the document from ArangoDB
|
|
||||||
*
|
|
||||||
* @return bool Writed to ArangoDB without errors?
|
|
||||||
*/
|
|
||||||
public static function _update(_document $instance): bool
|
|
||||||
{
|
|
||||||
// Update in ArangoDB and exit (success)
|
|
||||||
return document::update(static::$arangodb->session, $instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete from ArangoDB
|
|
||||||
*
|
|
||||||
* @param _document $instance Instance of the document from ArangoDB
|
|
||||||
* @param array &$errors The registry on errors
|
|
||||||
*
|
|
||||||
* @return bool Deleted from ArangoDB without errors?
|
|
||||||
*/
|
|
||||||
public static function _delete(_document $instance, array &$errors = []): bool
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (collection::init(static::$arangodb->session, static::COLLECTION)) {
|
|
||||||
// Initialized the collection
|
|
||||||
|
|
||||||
// Delete from ArangoDB and exit (success)
|
|
||||||
return (new _document_handler(static::$arangodb->session))->remove($instance);
|
|
||||||
} else throw new exception('Failed to initialize the collection');
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Write to the registry of errors
|
|
||||||
$errors[] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit (fail)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write
|
* Write
|
||||||
*
|
*
|
||||||
|
@ -205,7 +171,7 @@ class core extends model
|
||||||
if ($value instanceof arangodb) {
|
if ($value instanceof arangodb) {
|
||||||
// Recieved an appropriate value
|
// Recieved an appropriate value
|
||||||
|
|
||||||
// Write the property and exit (success)
|
// Writing the property and exit (success)
|
||||||
self::$arangodb = $value;
|
self::$arangodb = $value;
|
||||||
} else {
|
} else {
|
||||||
// Recieved an inappropriate value
|
// Recieved an inappropriate value
|
||||||
|
|
|
@ -0,0 +1,318 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Library for ArangoDB
|
||||||
|
use ArangoDBClient\Document as _document;
|
||||||
|
|
||||||
|
// Framework for ArangoDB
|
||||||
|
use mirzaev\arangodb\collection,
|
||||||
|
mirzaev\arangodb\document,
|
||||||
|
mirzaev\arangodb\enumerations\collection\type;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model of entry
|
||||||
|
*
|
||||||
|
* @package mirzaev\arming_bot\models
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class entry extends core implements arangodb_document_interface
|
||||||
|
{
|
||||||
|
use arangodb_document_trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the collection in ArangoDB
|
||||||
|
*/
|
||||||
|
final public const string COLLECTION = 'entry';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of the collection in ArangoDB
|
||||||
|
*/
|
||||||
|
public const type TYPE = type::edge;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write an entry
|
||||||
|
*
|
||||||
|
* @param category|product $from Descendant document
|
||||||
|
* @param category $to Ascendant document
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return string|null Identifier (_id) of instance of the entry document in ArangoDB, if created
|
||||||
|
*/
|
||||||
|
public static function write(
|
||||||
|
category|product $from,
|
||||||
|
category $to,
|
||||||
|
array &$errors = []
|
||||||
|
): string|null {
|
||||||
|
try {
|
||||||
|
if (collection::initialize($from::COLLECTION, $from::TYPE, errors: $errors)) {
|
||||||
|
if (collection::initialize($to::COLLECTION, $to::TYPE, errors: $errors)) {
|
||||||
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
|
// Initialized collections
|
||||||
|
|
||||||
|
// Creating the entry and exit (success)
|
||||||
|
return document::write(
|
||||||
|
static::COLLECTION,
|
||||||
|
[
|
||||||
|
'_from' => $from->getId(),
|
||||||
|
'_to' => $to->getId(),
|
||||||
|
'version' => ROBOT_VERSION ?? '0.0.0'
|
||||||
|
],
|
||||||
|
errors: $errors
|
||||||
|
);
|
||||||
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
|
} else throw new exception('Failed to initialize ' . $to::TYPE . ' collection: ' . $to::COLLECTION);
|
||||||
|
} else throw new exception('Failed to initialize ' . $from::TYPE . ' collection: ' . $from::COLLECTION);
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find ascendants
|
||||||
|
*
|
||||||
|
* Find ascendants that are not descendants for anyone
|
||||||
|
*
|
||||||
|
* @param category|product $descendant Descendant document
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return array|null Ascendants that are not descendants for anyone, if found
|
||||||
|
*/
|
||||||
|
public static function ascendants(
|
||||||
|
category|product $descendant,
|
||||||
|
array &$errors = []
|
||||||
|
): ?array {
|
||||||
|
try {
|
||||||
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
|
// Initialized the collection
|
||||||
|
if ($ascendants = collection::execute(
|
||||||
|
<<<'AQL'
|
||||||
|
FOR d IN @@collection
|
||||||
|
FOR ascendant IN OUTBOUND d @@edge
|
||||||
|
RETURN DISTINCT ascendant
|
||||||
|
AQL,
|
||||||
|
[
|
||||||
|
'@collection' => $descendant::COLLECTION,
|
||||||
|
'@edge' => static::COLLECTION
|
||||||
|
],
|
||||||
|
errors: $errors
|
||||||
|
)) {
|
||||||
|
// Found ascendants
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return is_array($ascendants) ? $ascendants : [$ascendants];
|
||||||
|
} else return [];
|
||||||
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check existence of entry between documents
|
||||||
|
*
|
||||||
|
* @param category|product $from Descendant document
|
||||||
|
* @param category $to Ascendant document
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return ?_document The entry edge, if found
|
||||||
|
*/
|
||||||
|
public static function check(
|
||||||
|
category|product $from,
|
||||||
|
category $to,
|
||||||
|
array &$errors = []
|
||||||
|
): ?_document {
|
||||||
|
try {
|
||||||
|
if (collection::initialize($from::COLLECTION, $from::TYPE, errors: $errors)) {
|
||||||
|
if (collection::initialize($to::COLLECTION, $to::TYPE, errors: $errors)) {
|
||||||
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
|
// Initialized collections
|
||||||
|
|
||||||
|
if ($entry = collection::execute(
|
||||||
|
<<<'AQL'
|
||||||
|
FOR d IN @@collection
|
||||||
|
FILTER d._from == @from && d._to == @to
|
||||||
|
SORT d.updated DESC, d.created DESC
|
||||||
|
LIMIT 1
|
||||||
|
RETURN d
|
||||||
|
AQL,
|
||||||
|
[
|
||||||
|
'@collection' => static::COLLECTION,
|
||||||
|
'from' => $from->getId(),
|
||||||
|
'to' => $to->getId()
|
||||||
|
],
|
||||||
|
errors: $errors
|
||||||
|
)) {
|
||||||
|
// Found the entry between $from and $to
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return is_array($entry) ? $entry[0] : $entry;
|
||||||
|
} else return null;
|
||||||
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
|
} else throw new exception('Failed to initialize ' . $to::TYPE . ' collection: ' . $to::COLLECTION);
|
||||||
|
} else throw new exception('Failed to initialize ' . $from::TYPE . ' collection: ' . $from::COLLECTION);
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поиск вхождений (подкатегории или товары)
|
||||||
|
*
|
||||||
|
* Находит вхождения через ребро entry
|
||||||
|
* Генерирует _type со значениями "category" и "product"
|
||||||
|
* относительно того есть ли у документа ещё вложения
|
||||||
|
* (подразумевается, что у product вложений быть не может)
|
||||||
|
* Объединяет возвращаемые объекты документа с переменной _type
|
||||||
|
*
|
||||||
|
* @param category|product $document Ascendant document
|
||||||
|
* @param string|null $filter Expression for filtering (AQL)
|
||||||
|
* @param string|null $sort Expression for sorting (AQL)
|
||||||
|
* @param int $page Страница
|
||||||
|
* @param int $amount Количество товаров на странице
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return array Массив с найденными вхождениями (может быть пустым)
|
||||||
|
*/
|
||||||
|
public static function search(
|
||||||
|
category|product $document,
|
||||||
|
?string $filter = 'v.deleted != true && v.hidden != true',
|
||||||
|
?string $sort = 'v.position ASC, v.created DESC',
|
||||||
|
int $page = 1,
|
||||||
|
int $amount = 100,
|
||||||
|
array &$errors = []
|
||||||
|
): array {
|
||||||
|
try {
|
||||||
|
if (collection::initialize($document::COLLECTION, $document::TYPE, errors: $errors)) {
|
||||||
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
|
// Initialized collections
|
||||||
|
|
||||||
|
if ($documents = collection::execute(
|
||||||
|
sprintf(
|
||||||
|
<<<'AQL'
|
||||||
|
FOR v IN 1..1 INBOUND @document GRAPH @graph
|
||||||
|
%s
|
||||||
|
%s
|
||||||
|
LIMIT @offset, @amount
|
||||||
|
LET _type = (FOR v2 IN INBOUND v._id GRAPH @graph RETURN v2)[0] ? "category" : "product"
|
||||||
|
RETURN MERGE(v, {_type})
|
||||||
|
AQL,
|
||||||
|
empty($filter) ? '' : "FILTER $filter",
|
||||||
|
empty($sort) ? '' : "SORT $sort",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
'grapth' => '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 [];
|
||||||
|
} 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) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Banish the document from the catalog
|
||||||
|
*
|
||||||
|
* Removes all entry edges associated with the document
|
||||||
|
*
|
||||||
|
* @param categoru|product $document Document for banishing
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function banish(category|product $document, array &$errors = []): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (collection::initialize($document::COLLECTION, $document::TYPE, errors: $errors)) {
|
||||||
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
|
// Initialized collections
|
||||||
|
|
||||||
|
// Execute and exit (success)
|
||||||
|
collection::execute(
|
||||||
|
<<<'AQL'
|
||||||
|
FOR d IN @@collection
|
||||||
|
// FILTER d._from == @_id || d._to == @_id
|
||||||
|
FILTER d._from == @_id
|
||||||
|
REMOVE d IN @@collection
|
||||||
|
AQL,
|
||||||
|
[
|
||||||
|
'@collection' => static::COLLECTION,
|
||||||
|
'_id' => $document->getId()
|
||||||
|
],
|
||||||
|
errors: $errors
|
||||||
|
);
|
||||||
|
} 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) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
|
||||||
|
|
||||||
// Files of the project
|
|
||||||
use mirzaev\arming_bot\models\categories;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Model of a part
|
|
||||||
*
|
|
||||||
* @package mirzaev\arming_bot\models
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
final class part extends categories
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Name of the collection in ArangoDB
|
|
||||||
*/
|
|
||||||
final public const string COLLECTION = 'part';
|
|
||||||
}
|
|
|
@ -5,15 +5,13 @@ declare(strict_types=1);
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\arming_bot\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core;
|
use mirzaev\arming_bot\models\core,
|
||||||
|
mirzaev\arming_bot\models\traits\document as arangodb_document_trait;
|
||||||
|
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\collection,
|
use mirzaev\arangodb\collection,
|
||||||
mirzaev\arangodb\document;
|
mirzaev\arangodb\document;
|
||||||
|
|
||||||
// Library для ArangoDB
|
|
||||||
use ArangoDBClient\Document as _document;
|
|
||||||
|
|
||||||
// Built-in libraries
|
// Built-in libraries
|
||||||
use exception;
|
use exception;
|
||||||
|
|
||||||
|
@ -21,155 +19,60 @@ use exception;
|
||||||
* Model of a product
|
* Model of a product
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\arming_bot\models
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
*/
|
*/
|
||||||
final class product extends core
|
final class product extends core
|
||||||
{
|
{
|
||||||
|
use arangodb_document_trait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the collection in ArangoDB
|
* Name of the collection in ArangoDB
|
||||||
*/
|
*/
|
||||||
final public const string COLLECTION = 'product';
|
final public const string COLLECTION = 'product';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Чтение товаров
|
* Write a product
|
||||||
*
|
*
|
||||||
* @param string|null $search Поиск
|
* @param int $identifier Identifier (unique)
|
||||||
* @param string|null $filter Фильтр
|
* @param array $name Name [['en' => value], ['ru' => значение]]
|
||||||
* @param string|null $sort Сортировка
|
* @param array|null $description Description [['en' => value], ['ru' => значение]]
|
||||||
* @param int $page Страница
|
* @param float $cost Cost
|
||||||
* @param int $amount Количество товаров на странице
|
* @param float $weight Weight
|
||||||
* @param string|null $return
|
* @param array $dimensions Dimensions ['x' => 0.0, 'y' => 0.0, 'z' => 0.0]
|
||||||
|
* @param array $images Images (first will be thumbnail)
|
||||||
|
* @param int|null $position Position for sorting in the catalog (ASC)
|
||||||
|
* @param array $data Data
|
||||||
* @param array &$errors Registry of errors
|
* @param array &$errors Registry of errors
|
||||||
*
|
*
|
||||||
* @return array Массив с найденными товарами (может быть пустым)
|
* @return string|null Identifier (_id) of instance of the product document in ArangoDB, if created
|
||||||
*/
|
|
||||||
public static function read(
|
|
||||||
?string $search = null,
|
|
||||||
?string $filter = 'd.deleted != true && d.hidden != true',
|
|
||||||
?string $sort = 'd.promotion DESC, d.position ASC, d.created DESC',
|
|
||||||
int $page = 1,
|
|
||||||
int $amount = 100,
|
|
||||||
?string $return = 'd',
|
|
||||||
array &$errors = []
|
|
||||||
): array {
|
|
||||||
try {
|
|
||||||
if (collection::init(core::$arangodb->session, self::COLLECTION)) {
|
|
||||||
// Инициализирована коллекция
|
|
||||||
|
|
||||||
// Инициализация строки запроса
|
|
||||||
$aql = sprintf(
|
|
||||||
<<<AQL
|
|
||||||
FOR d IN %s
|
|
||||||
AQL,
|
|
||||||
$search ? self::COLLECTION . 's_search' : self::COLLECTION
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($search) {
|
|
||||||
// Search
|
|
||||||
$aql .= sprintf(
|
|
||||||
<<<AQL
|
|
||||||
SEARCH
|
|
||||||
LEVENSHTEIN_MATCH(
|
|
||||||
d.title.ru,
|
|
||||||
TOKENS("%s", "text_ru")[0],
|
|
||||||
1,
|
|
||||||
false
|
|
||||||
) OR
|
|
||||||
levenshtein_match(
|
|
||||||
d.description.ru,
|
|
||||||
tokens("%s", "text_ru")[0],
|
|
||||||
1,
|
|
||||||
false
|
|
||||||
) OR
|
|
||||||
levenshtein_match(
|
|
||||||
d.compatibility.ru,
|
|
||||||
tokens("%s", "text_ru")[0],
|
|
||||||
1,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
AQL,
|
|
||||||
$search,
|
|
||||||
$search,
|
|
||||||
$search
|
|
||||||
);
|
|
||||||
|
|
||||||
// Adding sorting
|
|
||||||
if ($sort) $sort = "BM25(d) DESC, $sort";
|
|
||||||
else $sort = "BM25(d) DESC";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($documents = collection::search(
|
|
||||||
core::$arangodb->session,
|
|
||||||
sprintf(
|
|
||||||
$aql . <<<AQL
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
LIMIT %u, %u
|
|
||||||
RETURN %s
|
|
||||||
AQL,
|
|
||||||
empty($filter) ? '' : "FILTER $filter",
|
|
||||||
empty($sort) ? '' : "SORT $sort",
|
|
||||||
--$page <= 0 ? $page = 0 : $page * $amount,
|
|
||||||
$amount,
|
|
||||||
empty($return) ? 'd' : $return
|
|
||||||
)
|
|
||||||
)) {
|
|
||||||
// Найдены товары
|
|
||||||
|
|
||||||
// Возврат (успех)
|
|
||||||
return is_array($documents) ? $documents : [$documents];
|
|
||||||
} else return [];
|
|
||||||
} else throw new exception('Failed to initialize document collection: ' . self::COLLECTION);
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Write to the registry of errors
|
|
||||||
$errors[] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Выход (провал)
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Запись товара
|
|
||||||
*
|
*
|
||||||
* @param string $title Заголовок
|
* @todo
|
||||||
* @param string|null $description Описание
|
* 1. Bind parameters
|
||||||
* @param float $cost Цена
|
|
||||||
* @param float $weight Вес
|
|
||||||
* @param array $dimensions Габариты (float)
|
|
||||||
* @param array $images Изображения (первое - обложка) (https, путь в storage, иначе будет поиск в storage)
|
|
||||||
* @param array $hierarchy Иерархия вложенности (от родителей к потомкам: [ model, model ... ])
|
|
||||||
* @param array $data Дополнительные данные
|
|
||||||
* @param array &$errors Registry of errors
|
|
||||||
*
|
|
||||||
* @return string|null Идентификатор (_id) документа (товара), если создан
|
|
||||||
*/
|
*/
|
||||||
public static function write(
|
public static function write(
|
||||||
string $title,
|
int $identifier,
|
||||||
?string $description = null,
|
array $name = [['en' => 'ERROR']],
|
||||||
|
?array $description = [['en' => 'ERROR']],
|
||||||
float $cost = 0,
|
float $cost = 0,
|
||||||
float $weight = 0,
|
float $weight = 0,
|
||||||
array $dimensions = ['x' => 0, 'y' => 0, 'z' => 0],
|
array $dimensions = ['x' => 0, 'y' => 0, 'z' => 0],
|
||||||
array $images = [],
|
array $images = [],
|
||||||
array $hierarchy = [],
|
?int $position = null,
|
||||||
array $data = [],
|
array $data = [],
|
||||||
array &$errors = []
|
array &$errors = []
|
||||||
): string|null {
|
): string|null {
|
||||||
try {
|
try {
|
||||||
if (collection::init(core::$arangodb->session, self::COLLECTION)) {
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
// Инициализирована коллекция
|
// Initialized the collection
|
||||||
|
|
||||||
// Создание товара
|
// Writing in ArangoDB and exit (success)
|
||||||
$product = document::write(
|
return document::write(
|
||||||
core::$arangodb->session,
|
static::COLLECTION,
|
||||||
self::COLLECTION,
|
|
||||||
[
|
[
|
||||||
'title' => $title,
|
'identifier' => $identifier,
|
||||||
|
'name' => $name,
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
'cost' => $cost ?? 0,
|
'cost' => $cost ?? 0,
|
||||||
'weight' => $weight ?? 0,
|
'weight' => $weight ?? 0,
|
||||||
|
@ -179,31 +82,14 @@ final class product extends core
|
||||||
'z' => $dimensions['z'] ?? 0,
|
'z' => $dimensions['z'] ?? 0,
|
||||||
],
|
],
|
||||||
'images' => $images,
|
'images' => $images,
|
||||||
|
'position' => $position,
|
||||||
'version' => ROBOT_VERSION
|
'version' => ROBOT_VERSION
|
||||||
] + $data
|
] + $data,
|
||||||
|
errors: $errors
|
||||||
);
|
);
|
||||||
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
if ($product) {
|
|
||||||
// Создан товар
|
|
||||||
|
|
||||||
if (collection::init(core::$arangodb->session, 'entry', true)) {
|
|
||||||
// Инициализирована коллекция
|
|
||||||
|
|
||||||
foreach ($hierarchy as $model) {
|
|
||||||
// Перебор иерархической структуры категорий
|
|
||||||
|
|
||||||
// Инициализация вложенной категории (следующей в массиве)
|
|
||||||
$next = current($hierarchy);
|
|
||||||
|
|
||||||
// Поиск ребра описывающего иерархическую связь
|
|
||||||
|
|
||||||
document::write(core::$arangodb->session, 'entry');
|
|
||||||
}
|
|
||||||
} else throw new exception('Failed to initialize document collection: ' . self::COLLECTION);
|
|
||||||
}
|
|
||||||
} else throw new exception('Failed to initialize document collection: entry');
|
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
@ -212,7 +98,163 @@ final class product extends core
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Выход (провал)
|
// Exit (fail)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read products
|
||||||
|
*
|
||||||
|
* @param string|null $search Search (text)
|
||||||
|
* @param string|null $filter Flter (AQL)
|
||||||
|
* @param string|null $sort Sort (AQL)
|
||||||
|
* @param int $page Page
|
||||||
|
* @param int $amount Amount per page
|
||||||
|
* @param string|null $return Return (AQL)
|
||||||
|
* @param string $language Language code (en, ru...)
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return array Массив с найденными товарами (может быть пустым)
|
||||||
|
*/
|
||||||
|
public static function read(
|
||||||
|
?string $search = null,
|
||||||
|
?string $filter = 'd.deleted != true && d.hidden != true',
|
||||||
|
?string $sort = 'd.position ASC, d.created DESC',
|
||||||
|
int $page = 1,
|
||||||
|
int $amount = 100,
|
||||||
|
?string $return = 'd',
|
||||||
|
string $language = 'en',
|
||||||
|
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;
|
||||||
|
|
||||||
|
if ($search) {
|
||||||
|
// Requested search
|
||||||
|
|
||||||
|
// Writing to the query
|
||||||
|
$aql .= <<<'AQL'
|
||||||
|
SEARCH
|
||||||
|
LEVENSHTEIN_MATCH(
|
||||||
|
d.name.@language,
|
||||||
|
TOKENS(@search, @analyzer)[0],
|
||||||
|
1,
|
||||||
|
false
|
||||||
|
) OR
|
||||||
|
levenshtein_match(
|
||||||
|
d.description.@language,
|
||||||
|
tokens(@search, @analyzer)[0],
|
||||||
|
1,
|
||||||
|
false
|
||||||
|
) OR
|
||||||
|
levenshtein_match(
|
||||||
|
d.compatibility.@language,
|
||||||
|
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($return) ? 'd' : $return
|
||||||
|
),
|
||||||
|
[
|
||||||
|
'@collection' => $search ? static::COLLECTION . 's_search' : static::COLLECTION,
|
||||||
|
'search' => $search,
|
||||||
|
'language' => $language,
|
||||||
|
'analyzer' => "text_$language",
|
||||||
|
'offset' => --$page <= 0 ? $page = 0 : $page * $amount,
|
||||||
|
'amount' => $amount,
|
||||||
|
],
|
||||||
|
errors: $errors
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($documents) {
|
||||||
|
// Found products
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return is_array($documents) ? $documents : [$documents];
|
||||||
|
} else return [];
|
||||||
|
} else throw new exception('Failed to initialize ' . static::COLLECTION . ' collection: ' . static::COLLECTION);
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect parameter from all products
|
||||||
|
*
|
||||||
|
* @param string $name Name of the parameter (AQL path)
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return array Array with found unique parameter values from all products (can be empty)
|
||||||
|
*/
|
||||||
|
public static function collect(
|
||||||
|
string $name = 'd._key',
|
||||||
|
array &$errors = []
|
||||||
|
): array {
|
||||||
|
try {
|
||||||
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
|
// Initialized the collection
|
||||||
|
|
||||||
|
if ($values = collection::execute(
|
||||||
|
<<<'AQL'
|
||||||
|
FOR d IN @@collecton
|
||||||
|
RETURN DISTINCT @parameter
|
||||||
|
AQL,
|
||||||
|
[
|
||||||
|
'@collection' => static::COLLECTION,
|
||||||
|
'parameter' => $name
|
||||||
|
],
|
||||||
|
errors: $errors
|
||||||
|
)) {
|
||||||
|
// Found parameters
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $values;
|
||||||
|
} else return [];
|
||||||
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace mirzaev\arming_bot\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\account,
|
use mirzaev\arming_bot\models\account,
|
||||||
|
mirzaev\arming_bot\models\connect,
|
||||||
mirzaev\arming_bot\models\enumerations\session as verification,
|
mirzaev\arming_bot\models\enumerations\session as verification,
|
||||||
mirzaev\arming_bot\models\traits\status,
|
mirzaev\arming_bot\models\traits\status,
|
||||||
mirzaev\arming_bot\models\traits\document as arangodb_document_trait,
|
mirzaev\arming_bot\models\traits\document as arangodb_document_trait,
|
||||||
|
@ -25,6 +26,8 @@ use exception;
|
||||||
* Model of a session
|
* Model of a session
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\arming_bot\models
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
*/
|
*/
|
||||||
final class session extends core implements arangodb_document_interface
|
final class session extends core implements arangodb_document_interface
|
||||||
|
@ -37,12 +40,12 @@ final class session extends core implements arangodb_document_interface
|
||||||
final public const string COLLECTION = 'session';
|
final public const string COLLECTION = 'session';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of session verification(
|
* Type of sessions verification
|
||||||
*/
|
*/
|
||||||
public const verification VERIFICATION = verification::hash_else_address;
|
public const verification VERIFICATION = verification::hash_else_address;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor of an instance
|
* Constructor of instance
|
||||||
*
|
*
|
||||||
* Initialize of a session and write them to the $this->document property
|
* Initialize of a session and write them to the $this->document property
|
||||||
*
|
*
|
||||||
|
@ -50,63 +53,69 @@ final class session extends core implements arangodb_document_interface
|
||||||
* @param ?int $expires Date of expiring of the session (used for creating a new session)
|
* @param ?int $expires Date of expiring of the session (used for creating a new session)
|
||||||
* @param array &$errors Registry of errors
|
* @param array &$errors Registry of errors
|
||||||
*
|
*
|
||||||
* @return static instance of the ArangoDB document of session
|
* @return static
|
||||||
*/
|
*/
|
||||||
public function __construct(?string $hash = null, ?int $expires = null, array &$errors = [])
|
public function __construct(?string $hash = null, ?int $expires = null, array &$errors = [])
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (collection::init(static::$arangodb->session, self::COLLECTION)) {
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
// Initialized the collection
|
// Initialized the collection
|
||||||
|
|
||||||
if (isset($hash) && $document = $this->hash($hash, $errors)) {
|
if (isset($hash) && $document = $this->hash($hash, errors: $errors)) {
|
||||||
// Found an instance of the ArangoDB document of session and received a session hash
|
// Found the instance of the ArangoDB document of session and received a session hash
|
||||||
|
|
||||||
// Writing document instance of the session from ArangoDB to the property of the implementing object
|
// Writing document instance of the session from ArangoDB to the property of the implementing object
|
||||||
$this->document = $document;
|
$this->__document($document);
|
||||||
} else if (static::VERIFICATION === verification::hash_else_address && $document = $this->address($_SERVER['REMOTE_ADDR'], $errors)) {
|
} else if (static::VERIFICATION === verification::hash_else_address && $document = $this->address($_SERVER['REMOTE_ADDR'], errors: $errors)) {
|
||||||
// Found an instance of the ArangoDB document of session and received a session hash
|
// Found the instance of the ArangoDB document of session and received a session hash
|
||||||
|
|
||||||
// Writing document instance of the session from ArangoDB to the property of the implementing object
|
// Writing document instance of the session from ArangoDB to the property of the implementing object
|
||||||
$this->document = $document;
|
$this->__document($document);
|
||||||
} else {
|
} else {
|
||||||
// Not found an instance of the ArangoDB document of session
|
// Not found the instance of the ArangoDB document of session
|
||||||
|
|
||||||
// Initializing a new session and write they into ArangoDB
|
// Initializing a new session and write they into ArangoDB
|
||||||
$_id = document::write($this::$arangodb->session, self::COLLECTION, [
|
$_id = document::write(
|
||||||
|
static::COLLECTION,
|
||||||
|
[
|
||||||
'active' => true,
|
'active' => true,
|
||||||
'expires' => $expires ?? time() + 604800,
|
'expires' => $expires ?? time() + 604800,
|
||||||
'address' => $_SERVER['REMOTE_ADDR'],
|
'address' => $_SERVER['REMOTE_ADDR'],
|
||||||
'x-forwarded-for' => $_SERVER['HTTP_X_FORWARDED_FOR'] ?? null,
|
'x-forwarded-for' => $_SERVER['HTTP_X_FORWARDED_FOR'] ?? null,
|
||||||
'referer' => $_SERVER['HTTP_REFERER'] ?? null,
|
'referer' => $_SERVER['HTTP_REFERER'] ?? null,
|
||||||
'useragent' => $_SERVER['HTTP_USER_AGENT'] ?? null
|
'useragent' => $_SERVER['HTTP_USER_AGENT'] ?? null
|
||||||
]);
|
]
|
||||||
|
);
|
||||||
|
|
||||||
if ($session = collection::search($this::$arangodb->session, sprintf(
|
if ($session = collection::execute(
|
||||||
<<<AQL
|
<<<'AQL'
|
||||||
FOR d IN %s
|
FOR d IN @@collection
|
||||||
FILTER d._id == '%s' && d.expires > %d && d.active == true
|
FILTER d._id == @_id && d.expires > @time && d.active == true
|
||||||
RETURN d
|
RETURN d
|
||||||
AQL,
|
AQL,
|
||||||
self::COLLECTION,
|
[
|
||||||
$_id,
|
'@collection' => static::COLLECTION,
|
||||||
time()
|
'_id' => $_id,
|
||||||
))) {
|
'time' => time()
|
||||||
// Found an instance of just created new session
|
],
|
||||||
|
errors: $errors
|
||||||
|
)) {
|
||||||
|
// Found the instance of just created new session
|
||||||
|
|
||||||
// Generate a hash and write into an instance of the ArangoDB document of session property
|
// Generating a hash and write into the instance of the ArangoDB document of session property
|
||||||
$session->hash = sodium_bin2hex(sodium_crypto_generichash($_id));
|
$session->hash = sodium_bin2hex(sodium_crypto_generichash($_id));
|
||||||
|
|
||||||
if (document::update($this::$arangodb->session, $session)) {
|
if (document::update($session, errors: $errors)) {
|
||||||
// Is writed update
|
// Update is writed to ArangoDB
|
||||||
|
|
||||||
// Writing document instance of the session from ArangoDB to the property of the implementing object
|
// Writing instance of the session document from ArangoDB to the property of the implementing object
|
||||||
$this->document = $session;
|
$this->__document($session);
|
||||||
} else throw new exception('Could not write the session data');
|
} else throw new exception('Failed to write the session data');
|
||||||
} else throw new exception('Could not create or find just created session');
|
} else throw new exception('Failed to create or find just created session');
|
||||||
}
|
}
|
||||||
} else throw new exception('Could not initialize the collection');
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
@ -121,44 +130,47 @@ final class session extends core implements arangodb_document_interface
|
||||||
*
|
*
|
||||||
* @param array &$errors Registry of errors
|
* @param array &$errors Registry of errors
|
||||||
*
|
*
|
||||||
* @return account|null An object implementing the account instance from the database, if found
|
* @return account|null An object implements the instance of the account document from ArangoDB, if found
|
||||||
*/
|
*/
|
||||||
public function account(array &$errors = []): ?account
|
public function account(array &$errors = []): ?account
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (collection::init(core::$arangodb->session, static::COLLECTION)) {
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
if (collection::init(core::$arangodb->session, 'connect', true)) {
|
if (collection::initialize(connect::COLLECTION, connect::TYPE, errors: $errors)) {
|
||||||
if (collection::init(core::$arangodb->session, account::COLLECTION)) {
|
if (collection::initialize(account::COLLECTION, account::TYPE, errors: $errors)) {
|
||||||
// Инициализирована коллекция
|
// Initialized collections
|
||||||
|
|
||||||
if ($document = collection::search(
|
// Search for connected account
|
||||||
core::$arangodb->session,
|
$document = collection::execute(
|
||||||
sprintf(
|
|
||||||
<<<AQL
|
<<<AQL
|
||||||
FOR v IN INBOUND "%s" GRAPH sessions
|
FOR v IN INBOUND @session GRAPH sessions
|
||||||
SORT v.created DESC
|
SORT v.created DESC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
RETURN v
|
RETURN v
|
||||||
AQL,
|
AQL,
|
||||||
$this->getId(),
|
[
|
||||||
)
|
'session' => $this->getId()
|
||||||
)) {
|
],
|
||||||
// Найден аккаунт
|
errors: $errors
|
||||||
|
);
|
||||||
|
|
||||||
// Инициализация объекта аккаунта
|
if ($document instanceof _document) {
|
||||||
|
// Found connected account
|
||||||
|
|
||||||
|
// Initializing the implement object of the instance of sesson document from ArangoDB
|
||||||
$account = new account;
|
$account = new account;
|
||||||
|
|
||||||
// Запись инстанции документа в объект
|
// Writing the instance of session document from ArangoDB to the implement object
|
||||||
$account->__document($document);
|
$account->__document($document);
|
||||||
|
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return $account;
|
return $account;
|
||||||
} else return null;
|
} else return null;
|
||||||
} else throw new exception('Failed to initialize document collection: ' . account::COLLECTION);
|
} else throw new exception('Failed to initialize ' . account::TYPE . ' collection: ' . account::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize edge collection: connect');
|
} else throw new exception('Failed to initialize ' . connect::TYPE . ' collection: ' . connect::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize document collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
@ -182,25 +194,28 @@ final class session extends core implements arangodb_document_interface
|
||||||
public function connect(account $account, array &$errors = []): ?string
|
public function connect(account $account, array &$errors = []): ?string
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (collection::init(core::$arangodb->session, static::COLLECTION)) {
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
if (collection::init(core::$arangodb->session, 'connect', true)) {
|
if (collection::initialize(connect::COLLECTION, connect::TYPE, errors: $errors)) {
|
||||||
if (collection::init(core::$arangodb->session, account::COLLECTION)) {
|
if (collection::initialize(account::COLLECTION, account::TYPE, errors: $errors)) {
|
||||||
// Collections initialized
|
// Collections initialized
|
||||||
|
|
||||||
|
// The instance of the session document from ArangoDB is initialized?
|
||||||
|
isset($this->document) || throw new exception('The instance of the sessoin document from ArangoDB is not initialized');
|
||||||
|
|
||||||
// Writing document and exit (success)
|
// Writing document and exit (success)
|
||||||
return document::write(
|
return document::write(
|
||||||
core::$arangodb->session,
|
connect::COLLECTION,
|
||||||
'connect',
|
|
||||||
[
|
[
|
||||||
'_from' => $account->getId(),
|
'_from' => $account->getId(),
|
||||||
'_to' => $this->document->getId()
|
'_to' => $this->document->getId()
|
||||||
]
|
],
|
||||||
|
errors: $errors
|
||||||
);
|
);
|
||||||
} else throw new exception('Failed to initialize document collection: ' . account::COLLECTION);
|
} else throw new exception('Failed to initialize ' . account::TYPE . ' collection: ' . account::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize edge collection: connect');
|
} else throw new exception('Failed to initialize ' . connect::TYPE . ' collection: ' . connect::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize document collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
@ -226,23 +241,26 @@ final class session extends core implements arangodb_document_interface
|
||||||
public static function hash(string $hash, array &$errors = []): ?_document
|
public static function hash(string $hash, array &$errors = []): ?_document
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (collection::init(core::$arangodb->session, static::COLLECTION)) {
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
// Collection initialized
|
// Collection initialized
|
||||||
|
|
||||||
// Search the session data in ArangoDB
|
// Search the session data in ArangoDB
|
||||||
return collection::search(static::$arangodb->session, sprintf(
|
return collection::execute(
|
||||||
<<<AQL
|
<<<'AQL'
|
||||||
FOR d IN %s
|
FOR d IN @@collection
|
||||||
FILTER d.hash == '%s' && d.expires > %d && d.active == true
|
FILTER d.hash == @hash && d.expires > $time && d.active == true
|
||||||
RETURN d
|
RETURN d
|
||||||
AQL,
|
AQL,
|
||||||
static::COLLECTION,
|
[
|
||||||
$hash,
|
'@collection' => static::COLLECTION,
|
||||||
time()
|
'hash' => $hash,
|
||||||
));
|
'time' => time()
|
||||||
} else throw new exception('Failed to initialize document collection: ' . static::COLLECTION);
|
],
|
||||||
|
errors: $errors
|
||||||
|
);
|
||||||
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
@ -268,23 +286,26 @@ final class session extends core implements arangodb_document_interface
|
||||||
public static function address(string $address, array &$errors = []): ?_document
|
public static function address(string $address, array &$errors = []): ?_document
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (collection::init(core::$arangodb->session, static::COLLECTION)) {
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
// Collection initialized
|
// Collection initialized
|
||||||
|
|
||||||
// Search the session data in ArangoDB
|
// Search the session data in ArangoDB
|
||||||
return collection::search(static::$arangodb->session, sprintf(
|
return collection::execute(
|
||||||
<<<AQL
|
<<<'AQL'
|
||||||
FOR d IN %s
|
FOR d IN @@collection
|
||||||
FILTER d.address == '%s' && d.expires > %d && d.active == true
|
FILTER d.address == @address && d.expires > @time && d.active == true
|
||||||
RETURN d
|
RETURN d
|
||||||
AQL,
|
AQL,
|
||||||
static::COLLECTION,
|
[
|
||||||
$address,
|
'@collection' => static::COLLECTION,
|
||||||
time()
|
'address' => $address,
|
||||||
));
|
'time' => time()
|
||||||
} else throw new exception('Failed to initialize document collection: ' . static::COLLECTION);
|
],
|
||||||
|
errors: $errors
|
||||||
|
);
|
||||||
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
@ -303,28 +324,28 @@ final class session extends core implements arangodb_document_interface
|
||||||
* @param array $data Data for merging
|
* @param array $data Data for merging
|
||||||
* @param array &$errors Registry of errors
|
* @param array &$errors Registry of errors
|
||||||
*
|
*
|
||||||
* @return bool Is data has written into the session buffer?
|
* @return bool Is data has written into the session document from ArangoDB?
|
||||||
*/
|
*/
|
||||||
public function write(array $data, array &$errors = []): bool
|
public function write(array $data, array &$errors = []): bool
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (collection::init($this::$arangodb->session, self::COLLECTION)) {
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
// Initialized the collection
|
// Initialized the collection
|
||||||
|
|
||||||
// An instance of the ArangoDB document of session is initialized?
|
// The instance of the session document from ArangoDB is initialized?
|
||||||
if (!isset($this->document)) throw new exception('An instance of the ArangoDB document of session is not initialized');
|
isset($this->document) || throw new exception('The instance of the sessoin document from ArangoDB is not initialized');
|
||||||
|
|
||||||
// Write data into buffwer of an instance of the ArangoDB document of session
|
// Writing data into buffer of the instance of the session document from ArangoDB
|
||||||
$this->document->buffer = array_replace_recursive(
|
$this->document->buffer = array_replace_recursive(
|
||||||
$this->document->buffer ?? [],
|
$this->document->buffer ?? [],
|
||||||
[$_SERVER['INTERFACE'] => array_replace_recursive($this->document->buffer[$_SERVER['INTERFACE']] ?? [], $data)]
|
[$_SERVER['INTERFACE'] => array_replace_recursive($this->document->buffer[$_SERVER['INTERFACE']] ?? [], $data)]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Write to ArangoDB and exit (success)
|
// Writing to ArangoDB and exit (success)
|
||||||
return document::update($this::$arangodb->session, $this->document) ? true : throw new exception('Не удалось записать данные в буфер сессии');
|
return document::update($this->document, errors: $errors);
|
||||||
} else throw new exception('Could not initialize the collection');
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
@ -333,6 +354,7 @@ final class session extends core implements arangodb_document_interface
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ use exception;
|
||||||
* Model of settings
|
* Model of settings
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\arming_bot\models
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
*/
|
*/
|
||||||
final class settings extends core implements arangodb_document_interface
|
final class settings extends core implements arangodb_document_interface
|
||||||
|
@ -40,35 +42,52 @@ final class settings extends core implements arangodb_document_interface
|
||||||
* @param array|null $create Данные для создания, если настройки не найдены
|
* @param array|null $create Данные для создания, если настройки не найдены
|
||||||
* @param array &$errors Registry of errors
|
* @param array &$errors Registry of errors
|
||||||
*
|
*
|
||||||
* @return static|null Object implements an instance of settngs document from ArangoDB
|
* @return static|null Object implements the instance of settngs document from ArangoDB
|
||||||
*/
|
*/
|
||||||
public static function active(array|null $create = null, array &$errors = []): static|null
|
public static function active(array|null $create = null, array &$errors = []): static|null
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (collection::init(core::$arangodb->session, self::COLLECTION)) {
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
if ($document = collection::search(core::$arangodb->session, sprintf("FOR d IN %s FILTER d.status == 'active' SORT d.updated DESC LIMIT 1 RETURN d", self::COLLECTION))) {
|
// Initialized the collection
|
||||||
// Найдены активные настройки
|
|
||||||
|
|
||||||
// Инициализация объекта настроек
|
// Search for active settings
|
||||||
|
$document = collection::execute(
|
||||||
|
<<<'AQL'
|
||||||
|
FOR d IN @@collection
|
||||||
|
FILTER d.status == 'active'
|
||||||
|
SORT d.updated DESC
|
||||||
|
LIMIT 1
|
||||||
|
RETURN d
|
||||||
|
AQL,
|
||||||
|
[
|
||||||
|
'@collection' => static::COLLECTION
|
||||||
|
],
|
||||||
|
errors: $errors
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($document instanceof _document) {
|
||||||
|
// Found active settings
|
||||||
|
|
||||||
|
// Initializing the implement object of the instance of settings document from ArangoDB
|
||||||
$settings = new static;
|
$settings = new static;
|
||||||
|
|
||||||
// Запись инстанции документа в объект
|
// Writing the instance of settings document from ArangoDB to the implement object
|
||||||
$settings->document = $document;
|
$settings->__document($document);
|
||||||
|
|
||||||
// Возврат (успех)
|
// Exit (success)
|
||||||
return $settings;
|
return $settings;
|
||||||
} else if ($create) {
|
} else if ($create) {
|
||||||
// Не найдены активные настройки и запрошено создание
|
// Not found active settings and requested their creating
|
||||||
|
|
||||||
// Создание настроек
|
// Creating a settings
|
||||||
document::write(core::$arangodb->session, self::COLLECTION, ['status' => 'active'] + $create);
|
document::write(static::COLLECTION, ['status' => 'active'] + $create, errors: $errors);
|
||||||
|
|
||||||
// Инициализация (без создания)
|
// Re-search (without creating) and exit (success || fail)
|
||||||
return static::active(errors: $errors);
|
return static::active(errors: $errors);
|
||||||
} else throw new exception('Settings not found');
|
} else throw new exception('Active settings not found');
|
||||||
} else throw new exception('Failed to initialize document collection: ' . self::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
@ -77,7 +96,7 @@ final class settings extends core implements arangodb_document_interface
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Выход (провал)
|
// Exit (fail)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ use exception,
|
||||||
* Model of a suspension
|
* Model of a suspension
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\arming_bot\models
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
*/
|
*/
|
||||||
final class suspension extends core implements arangodb_document_interface
|
final class suspension extends core implements arangodb_document_interface
|
||||||
|
@ -42,27 +44,45 @@ final class suspension extends core implements arangodb_document_interface
|
||||||
*
|
*
|
||||||
* @param array &$errors Registry of errors
|
* @param array &$errors Registry of errors
|
||||||
*
|
*
|
||||||
* @return static|null Object implements an instance of suspension from ArangoDB
|
* @return static|null Object implements the instance of suspension from ArangoDB
|
||||||
*/
|
*/
|
||||||
public static function search(array &$errors = []): static|null
|
public static function search(array &$errors = []): static|null
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (collection::init(core::$arangodb->session, self::COLLECTION)) {
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
if ($document = collection::search(core::$arangodb->session, sprintf("FOR d IN %s FILTER d.end > %u SORT d.end DESC LIMIT 1 RETURN d", self::COLLECTION, time()))) {
|
// Initialized the collection
|
||||||
// Найдены активные настройки
|
|
||||||
|
|
||||||
// Инициализация объекта настроек
|
// Search for active suspension
|
||||||
|
$document = collection::execute(
|
||||||
|
<<<'AQL'
|
||||||
|
FOR d IN @@collection
|
||||||
|
FILTER d.end > @time
|
||||||
|
SORT d.end DESC
|
||||||
|
LIMIT 1
|
||||||
|
RETURN d
|
||||||
|
AQL,
|
||||||
|
[
|
||||||
|
'@collection' => static::COLLECTION,
|
||||||
|
'time' => time()
|
||||||
|
],
|
||||||
|
errors: $errors
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($document instanceof _document) {
|
||||||
|
// Found active suspension
|
||||||
|
|
||||||
|
// Initializing the implement object of the instance of suspension document from ArangoDB
|
||||||
$suspension = new static;
|
$suspension = new static;
|
||||||
|
|
||||||
// Запись инстанции документа в объект
|
// Writing the instance of suspension document from ArangoDB to the implement object
|
||||||
$suspension->document = $document;
|
$suspension->__document($document);
|
||||||
|
|
||||||
// Возврат (успех)
|
// Exit (success)
|
||||||
return $suspension;
|
return $suspension;
|
||||||
} else return null;
|
} else return null;
|
||||||
} else throw new exception('Failed to initialize document collection: ' . self::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
@ -151,7 +171,7 @@ final class suspension extends core implements arangodb_document_interface
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
|
|
@ -7,26 +7,26 @@ namespace mirzaev\arming_bot\models;
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\arming_bot\models\core,
|
||||||
mirzaev\arming_bot\controllers\core as controller,
|
mirzaev\arming_bot\controllers\core as controller,
|
||||||
|
mirzaev\arming_bot\models\catalog,
|
||||||
|
mirzaev\arming_bot\models\suspension,
|
||||||
mirzaev\arming_bot\models\account;
|
mirzaev\arming_bot\models\account;
|
||||||
|
|
||||||
// Фреймворк Telegram
|
// Framework for Telegram
|
||||||
use Zanzara\Zanzara,
|
use Zanzara\Zanzara,
|
||||||
Zanzara\Context,
|
Zanzara\Context,
|
||||||
Zanzara\Telegram\Type\Input\InputFile,
|
Zanzara\Telegram\Type\Input\InputFile,
|
||||||
Zanzara\Telegram\Type\File\Document as telegram_document,
|
Zanzara\Telegram\Type\File\Document as telegram_document,
|
||||||
Zanzara\Telegram\Type\File\File,
|
|
||||||
Zanzara\Middleware\MiddlewareNode as Node;
|
Zanzara\Middleware\MiddlewareNode as Node;
|
||||||
|
|
||||||
// Library для ArangoDB
|
|
||||||
use ArangoDBClient\Document as _document;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model of a chat
|
* Model of chat (telegram)
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\arming_bot\models
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
*/
|
*/
|
||||||
final class chat extends core
|
final class telegram extends core
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Экранирование символов для Markdown
|
* Экранирование символов для Markdown
|
||||||
|
@ -167,7 +167,8 @@ final class chat extends core
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
['text' => '🪖 Сайт', 'url' => 'https://arming.ru'],
|
['text' => '🪖 Сайт', 'url' => 'https://arming.ru'],
|
||||||
['text' => '🛒 Wildberries', 'url' => 'https://arming.ru']
|
['text' => '🛒 Wildberries', 'url' => 'https://www.wildberries.ru/seller/137386'],
|
||||||
|
['text' => '🛒 Ozon', 'url' => 'https://www.ozon.ru/seller/arming-1086587/products/?miniapp=seller_1086587'],
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
@ -323,7 +324,7 @@ final class chat extends core
|
||||||
$ctx->sendDocument(new InputFile(CATALOG_EXAMPLE), ['disable_notification' => true]);
|
$ctx->sendDocument(new InputFile(CATALOG_EXAMPLE), ['disable_notification' => true]);
|
||||||
|
|
||||||
// Импорт файла
|
// Импорт файла
|
||||||
$ctx->nextStep("import");
|
$ctx->nextStep([static::class, 'import'], true);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Не авторизован доступ к настройкам
|
// Не авторизован доступ к настройкам
|
||||||
|
@ -342,7 +343,7 @@ final class chat extends core
|
||||||
*/
|
*/
|
||||||
public static function import(Context $ctx): void
|
public static function import(Context $ctx): void
|
||||||
{
|
{
|
||||||
if ($ctx->get('account')?->access['settings']) {
|
if (($account = $ctx->get('account'))?->access['settings']) {
|
||||||
// Авторизован доступ к настройкам
|
// Авторизован доступ к настройкам
|
||||||
|
|
||||||
// Инициализация документа
|
// Инициализация документа
|
||||||
|
@ -352,36 +353,98 @@ final class chat extends core
|
||||||
// Инициализирован документ
|
// Инициализирован документ
|
||||||
|
|
||||||
// Инициализация файла
|
// Инициализация файла
|
||||||
$ctx->getFile($document->getFileId())->then(function ($file) use ($ctx) {
|
$ctx->getFile($document->getFileId())->then(function ($file) use ($ctx, $document, $account) {
|
||||||
|
|
||||||
if ($file->getFileSize() <= 50000000) {
|
if ($file->getFileSize() <= 50000000) {
|
||||||
// Не превышает 50 мегабайт (50000000 байт) размер файла
|
// Не превышает 50 мегабайт (50 000 000 байт) размер файла
|
||||||
|
|
||||||
if ($file->getFilePath()['extension'] === 'xlsx') {
|
if (pathinfo(parse_url($file->getFilePath())['path'], PATHINFO_EXTENSION) === 'xlsx') {
|
||||||
// Имеет расширение xlsx файл
|
// Имеет расширение xlsx файл
|
||||||
|
|
||||||
|
// Initializing the directory in the storage
|
||||||
|
if (!file_exists($storage = STORAGE . DIRECTORY_SEPARATOR . 'import' . DIRECTORY_SEPARATOR . $account->getKey() . DIRECTORY_SEPARATOR . time()))
|
||||||
|
mkdir($storage, 0775, true);
|
||||||
|
|
||||||
// Сохранение файла
|
// Сохранение файла
|
||||||
file_put_contents(STORAGE . DIRECTORY_SEPARATOR . 'import.xlsx', file_get_contents('https://api.telegram.org/file/bot' . KEY . '/' . $file->getFilePath()));
|
file_put_contents(
|
||||||
|
$import = $storage . DIRECTORY_SEPARATOR . 'import.xlsx',
|
||||||
|
file_get_contents('https://api.telegram.org/file/bot' . KEY . '/' . parse_url($file->getFilePath())['path'])
|
||||||
|
);
|
||||||
|
|
||||||
|
// Отправка сообщения
|
||||||
|
$ctx->sendMessage(sprintf(
|
||||||
|
<<<'TXT'
|
||||||
|
🔬 *Выполняется анализ:* %s \(%s байт\)
|
||||||
|
TXT,
|
||||||
|
static::unmarkdown($document->getFileName()),
|
||||||
|
static::unmarkdown((string) $file->getFileSize())
|
||||||
|
))
|
||||||
|
->then(function ($message) use ($ctx, $import) {
|
||||||
// Инициализация счётчика загруженных товаров
|
// Инициализация счётчика загруженных товаров
|
||||||
$loaded = $created = $updated = $deleted = $old = $new = 0;
|
$categories_loaded
|
||||||
|
= $products_loaded
|
||||||
|
= $categories_created
|
||||||
|
= $products_created
|
||||||
|
= $categories_updated
|
||||||
|
= $products_updated
|
||||||
|
= $categories_deleted
|
||||||
|
= $products_deleted
|
||||||
|
= $categories_old
|
||||||
|
= $products_old
|
||||||
|
= $categories_new
|
||||||
|
= $products_new
|
||||||
|
= 0;
|
||||||
|
|
||||||
|
// Import
|
||||||
|
catalog::import(
|
||||||
|
$import,
|
||||||
|
$categories_loaded,
|
||||||
|
$categories_created,
|
||||||
|
$categories_updated,
|
||||||
|
$categories_deleted,
|
||||||
|
$categories_old,
|
||||||
|
$categories_new,
|
||||||
|
$products_loaded,
|
||||||
|
$products_created,
|
||||||
|
$products_updated,
|
||||||
|
$products_deleted,
|
||||||
|
$products_old,
|
||||||
|
$products_new,
|
||||||
|
language: 'ru'
|
||||||
|
);
|
||||||
|
|
||||||
// Отправка сообщения
|
// Отправка сообщения
|
||||||
$ctx->sendMessage(<<<TXT
|
$ctx->sendMessage(<<<TXT
|
||||||
*Загружено для обработки:* $loaded
|
🏷 *Категории*
|
||||||
|
|
||||||
*Добавлено:* $created
|
*Загружено:* $categories_loaded
|
||||||
*Обновлено:* $updated
|
|
||||||
*Удалено:* $deleted
|
|
||||||
|
|
||||||
*Опубликовано в магазине:* $old \-\> *$new*
|
*Добавлено:* $categories_created
|
||||||
|
*Обновлено:* $categories_updated
|
||||||
|
*Удалено:* $categories_deleted
|
||||||
|
|
||||||
|
*Было:* $categories_old
|
||||||
|
*Стало:* $categories_new
|
||||||
|
TXT)
|
||||||
|
->then(function ($message) use ($ctx, $products_loaded, $products_created, $products_updated, $products_deleted, $products_old, $products_new) {
|
||||||
|
$ctx->sendMessage(<<<TXT
|
||||||
|
📦 *Товары*
|
||||||
|
|
||||||
|
*Загружено:* $products_loaded
|
||||||
|
|
||||||
|
*Добавлено:* $products_created
|
||||||
|
*Обновлено:* $products_updated
|
||||||
|
*Удалено:* $products_deleted
|
||||||
|
|
||||||
|
*Было:* $products_old
|
||||||
|
*Стало:* $products_new
|
||||||
TXT)
|
TXT)
|
||||||
->then(function ($message) use ($ctx) {
|
->then(function ($message) use ($ctx) {
|
||||||
// Завершение диалога
|
// Завершение диалога
|
||||||
$ctx->endConversation();
|
$ctx->endConversation();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// Не имеет расширение xlsx файл
|
// Не имеет расширение xlsx файл
|
||||||
|
|
||||||
|
@ -473,7 +536,7 @@ final class chat extends core
|
||||||
// Поиск технических работ
|
// Поиск технических работ
|
||||||
$suspension = suspension::search();
|
$suspension = suspension::search();
|
||||||
|
|
||||||
if ($suspension && $suspension->targets['chat-robot']) {
|
if ($suspension && $suspension->targets['telegram-robot']) {
|
||||||
// Найдена активная приостановка
|
// Найдена активная приостановка
|
||||||
|
|
||||||
// Инициализация аккаунта
|
// Инициализация аккаунта
|
||||||
|
@ -501,7 +564,8 @@ final class chat extends core
|
||||||
$message = "⚠️ *Работа приостановлена*\n*Оставшееся время\:* " . $suspension->message($account->language ?? controller::$settings?->language);
|
$message = "⚠️ *Работа приостановлена*\n*Оставшееся время\:* " . $suspension->message($account->language ?? controller::$settings?->language);
|
||||||
|
|
||||||
// Добавление описания причины приостановки, если найдена
|
// Добавление описания причины приостановки, если найдена
|
||||||
if (!empty($suspension->description)) $message .= "\n\n" . $suspension->description[$account->language ?? controller::$settings?->language] ?? array_values($suspension->description)[0];
|
if (!empty($suspension->description))
|
||||||
|
$message .= "\n\n" . $suspension->description[$account->language ?? controller::$settings?->language] ?? array_values($suspension->description)[0];
|
||||||
|
|
||||||
// Отправка сообщения
|
// Отправка сообщения
|
||||||
$ctx->sendMessage($message)
|
$ctx->sendMessage($message)
|
||||||
|
@ -519,84 +583,4 @@ final class chat extends core
|
||||||
$next($ctx);
|
$next($ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Write
|
|
||||||
*
|
|
||||||
* Write a property into an instance of the ArangoDB document
|
|
||||||
*
|
|
||||||
* @param string $name Name of the property
|
|
||||||
* @param mixed $value Content of the property
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __set(string $name, mixed $value = null): void
|
|
||||||
{
|
|
||||||
// Write to the property into an instance of the ArangoDB document and exit (success)
|
|
||||||
$this->document->{$name} = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read
|
|
||||||
*
|
|
||||||
* Read a property from an instance of the ArangoDB docuemnt
|
|
||||||
*
|
|
||||||
* @param string $name Name of the property
|
|
||||||
*
|
|
||||||
* @return mixed Content of the property
|
|
||||||
*/
|
|
||||||
public function __get(string $name): mixed
|
|
||||||
{
|
|
||||||
// Read a property from an instance of the ArangoDB document and exit (success)
|
|
||||||
return match ($name) {
|
|
||||||
'arangodb' => $this::$arangodb,
|
|
||||||
default => $this->document->{$name}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete
|
|
||||||
*
|
|
||||||
* Deinitialize the property in an instance of the ArangoDB document
|
|
||||||
*
|
|
||||||
* @param string $name Name of the property
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __unset(string $name): void
|
|
||||||
{
|
|
||||||
// Delete the property in an instance of the ArangoDB document and exit (success)
|
|
||||||
unset($this->document->{$name});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check of initialization
|
|
||||||
*
|
|
||||||
* Check of initialization of the property into an instance of the ArangoDB document
|
|
||||||
*
|
|
||||||
* @param string $name Name of the property
|
|
||||||
*
|
|
||||||
* @return bool The property is initialized?
|
|
||||||
*/
|
|
||||||
public function __isset(string $name): bool
|
|
||||||
{
|
|
||||||
// Check of initializatio nof the property and exit (success)
|
|
||||||
return isset($this->document->{$name});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a method
|
|
||||||
*
|
|
||||||
* Execute a method from an instance of the ArangoDB document
|
|
||||||
*
|
|
||||||
* @param string $name Name of the method
|
|
||||||
* @param array $arguments Arguments for the method
|
|
||||||
*
|
|
||||||
* @return mixed Result of execution of the method
|
|
||||||
*/
|
|
||||||
public function __call(string $name, array $arguments = []): mixed
|
|
||||||
{
|
|
||||||
// Execute the method and exit (success)
|
|
||||||
if (method_exists($this->document, $name)) return $this->document->{$name}($arguments);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -10,9 +10,17 @@ use mirzaev\arming_bot\models\core;
|
||||||
// Library для ArangoDB
|
// Library для ArangoDB
|
||||||
use ArangoDBClient\Document as _document;
|
use ArangoDBClient\Document as _document;
|
||||||
|
|
||||||
|
// Framework for ArangoDB
|
||||||
|
use mirzaev\arangodb\connection as arangodb;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trait for implementing a document instance from ArangoDB
|
* Trait for implementing a document instance from ArangoDB
|
||||||
*
|
*
|
||||||
|
* @var protected readonly _document|null $document An instance of the ArangoDB document
|
||||||
|
*
|
||||||
* @package mirzaev\arming_bot\models\traits
|
* @package mirzaev\arming_bot\models\traits
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
*/
|
*/
|
||||||
|
@ -23,6 +31,28 @@ trait document
|
||||||
*/
|
*/
|
||||||
protected readonly _document $document;
|
protected readonly _document $document;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of an instance
|
||||||
|
*
|
||||||
|
* @param bool $initialize Initialize a model?
|
||||||
|
* @param ?arangodb $arangodb Instance of a session of ArangoDB
|
||||||
|
* @param _document|null|false $document An instance of the ArangoDB document
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
bool $initialize = true,
|
||||||
|
?arangodb $arangodb = null,
|
||||||
|
_document|null|false $document = false
|
||||||
|
) {
|
||||||
|
// For the extends system
|
||||||
|
parent::__construct($initialize, $arangodb);
|
||||||
|
|
||||||
|
// Writing to the property
|
||||||
|
if ($document instanceof _document) $this->document = $document;
|
||||||
|
else if ($document === null) throw new exception('Failed to initialize an instance of the document from ArangoDB');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write or read document
|
* Write or read document
|
||||||
*
|
*
|
||||||
|
@ -30,13 +60,13 @@ trait document
|
||||||
*
|
*
|
||||||
* @return _document|null Instance of document from ArangoDB
|
* @return _document|null Instance of document from ArangoDB
|
||||||
*/
|
*/
|
||||||
public function __document(?_document $document): ?_document
|
public function __document(?_document $document = null): ?_document
|
||||||
{
|
{
|
||||||
// Write a property storing a document instance to ArangoDB
|
// Writing a property storing a document instance to ArangoDB
|
||||||
if ($document) $this->document = $document;
|
if ($document) $this->document ??= $document;
|
||||||
|
|
||||||
// Read a property storing a document instance to ArangoDB and exit (success)
|
// Read a property storing a document instance to ArangoDB and exit (success)
|
||||||
return $this->document;
|
return $this->document ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,7 +81,7 @@ trait document
|
||||||
*/
|
*/
|
||||||
public function __set(string $name, mixed $value = null): void
|
public function __set(string $name, mixed $value = null): void
|
||||||
{
|
{
|
||||||
// Write to the property into an instance of the ArangoDB document and exit (success)
|
// Writing to the property into an instance of the ArangoDB document and exit (success)
|
||||||
$this->document->{$name} = $value;
|
$this->document->{$name} = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,6 +146,6 @@ trait document
|
||||||
public function __call(string $name, array $arguments = []): mixed
|
public function __call(string $name, array $arguments = []): mixed
|
||||||
{
|
{
|
||||||
// Execute the method and exit (success)
|
// Execute the method and exit (success)
|
||||||
return method_exists($this->document, $name) ?$this->document->{$name}($arguments) ?? null : null;
|
return method_exists($this->document, $name) ? $this->document->{$name}($arguments) ?? null : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace mirzaev\arming_bot\models\traits;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait for initialization of files handlers
|
||||||
|
*
|
||||||
|
* @package mirzaev\arming_bot\models\traits
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
trait files
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Delete files recursively
|
||||||
|
*
|
||||||
|
* @param string $directory Directory
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function delete(string $directory, array &$errors = []): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (file_exists($directory)) {
|
||||||
|
// Directory exists
|
||||||
|
|
||||||
|
// Deleting descendant files and directories (enter to the recursion)
|
||||||
|
foreach (scandir($directory) as $file) {
|
||||||
|
if ($file === '.' || $file === '..') continue;
|
||||||
|
else if (is_dir("$directory/$file")) static::delete("$directory/$file", $errors);
|
||||||
|
else unlink("$directory/$file");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deleting the directory
|
||||||
|
rmdir($directory);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return;
|
||||||
|
} else throw new exception('Directory does not exist');
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ trait status
|
||||||
// Read from ArangoDB and exit (success)
|
// Read from ArangoDB and exit (success)
|
||||||
return $this->document->active ?? false;
|
return $this->document->active ?? false;
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace mirzaev\arming_bot\models\traits\yandex;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait for "Yandex Disk"
|
||||||
|
*
|
||||||
|
* @package mirzaev\arming_bot\models\traits\yandex
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
trait disk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Download file from "Yandex Disk"
|
||||||
|
*
|
||||||
|
* @param string $uri URI of the file from "Yandex Disk"
|
||||||
|
* @param string $destination Destination to write the file
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return bool The file is downloaded?
|
||||||
|
*/
|
||||||
|
private static function download(
|
||||||
|
string $uri,
|
||||||
|
string $destination,
|
||||||
|
array &$errors = []
|
||||||
|
): bool {
|
||||||
|
try {
|
||||||
|
if (!empty($uri)) {
|
||||||
|
// Not empty URI
|
||||||
|
|
||||||
|
if (!empty($destination)) {
|
||||||
|
// Not empty destination
|
||||||
|
|
||||||
|
// Initializing URL of the file
|
||||||
|
$url = "https://cloud-api.yandex.net/v1/disk/public/resources/download?public_key=$uri";
|
||||||
|
|
||||||
|
// Checking if the file is available for download
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_exec($ch);
|
||||||
|
$code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($code === 200) {
|
||||||
|
// The file is available for download
|
||||||
|
|
||||||
|
// Downloading the file and exit (success)
|
||||||
|
return file_put_contents($destination, file_get_contents(json_decode(file_get_contents($url))?->href)) > 0;
|
||||||
|
} else throw new exception("File not available for download: $uri");
|
||||||
|
} else throw new exception("Empty destination");
|
||||||
|
} else throw new exception("Empty URI");
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Writing to the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,9 +12,9 @@ use mirzaev\arming_bot\controllers\core as controller,
|
||||||
use mirzaev\minimal\core,
|
use mirzaev\minimal\core,
|
||||||
mirzaev\minimal\router;
|
mirzaev\minimal\router;
|
||||||
|
|
||||||
/* ini_set('error_reporting', E_ALL);
|
ini_set('error_reporting', E_ALL);
|
||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 1);
|
||||||
ini_set('display_startup_errors', 1); */
|
ini_set('display_startup_errors', 1);
|
||||||
|
|
||||||
// Версия робота
|
// Версия робота
|
||||||
define('ROBOT_VERSION', '1.0.0');
|
define('ROBOT_VERSION', '1.0.0');
|
||||||
|
|
|
@ -15,7 +15,10 @@ import("/js/core.js").then(() =>
|
||||||
initialization();
|
initialization();
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
const timeout = setTimeout(() => clearInterval(dependencies), 5000);
|
const timeout = setTimeout(() => {
|
||||||
|
clearInterval(dependencies);
|
||||||
|
initialization();
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
function initialization() {
|
function initialization() {
|
||||||
const timer_for_response = setTimeout(() => {
|
const timer_for_response = setTimeout(() => {
|
||||||
|
|
|
@ -4,14 +4,19 @@
|
||||||
import("/js/core.js").then(() =>
|
import("/js/core.js").then(() =>
|
||||||
import("/js/damper.js").then(() => {
|
import("/js/damper.js").then(() => {
|
||||||
const dependencies = setInterval(() => {
|
const dependencies = setInterval(() => {
|
||||||
if (typeof core === "function" &&
|
if (
|
||||||
typeof core.damper === "function") {
|
typeof core === "function" &&
|
||||||
|
typeof core.damper === "function"
|
||||||
|
) {
|
||||||
clearInterval(dependencies);
|
clearInterval(dependencies);
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
initialization();
|
initialization();
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
const timeout = setTimeout(() => clearInterval(dependencies), 5000);
|
const timeout = setTimeout(() => {
|
||||||
|
clearInterval(dependencies);
|
||||||
|
initialization();
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
function initialization() {
|
function initialization() {
|
||||||
if (typeof core.cart === "undefined") {
|
if (typeof core.cart === "undefined") {
|
||||||
|
|
|
@ -6,7 +6,12 @@ import("/js/core.js").then(() =>
|
||||||
import("/js/telegram.js").then(() => {
|
import("/js/telegram.js").then(() => {
|
||||||
import("/js/hotline.js").then(() => {
|
import("/js/hotline.js").then(() => {
|
||||||
const dependencies = setInterval(() => {
|
const dependencies = setInterval(() => {
|
||||||
console.log(typeof core, typeof core.damper, typeof core.telegram, typeof core.hotline);
|
console.log(
|
||||||
|
typeof core,
|
||||||
|
typeof core.damper,
|
||||||
|
typeof core.telegram,
|
||||||
|
typeof core.hotline,
|
||||||
|
);
|
||||||
if (
|
if (
|
||||||
typeof core === "function" &&
|
typeof core === "function" &&
|
||||||
typeof core.damper === "function" &&
|
typeof core.damper === "function" &&
|
||||||
|
@ -18,7 +23,10 @@ import("/js/core.js").then(() =>
|
||||||
initialization();
|
initialization();
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
const timeout = setTimeout(() => clearInterval(dependencies), 5000);
|
const timeout = setTimeout(() => {
|
||||||
|
clearInterval(dependencies);
|
||||||
|
initialization();
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
function initialization() {
|
function initialization() {
|
||||||
if (typeof core.catalog === "undefined") {
|
if (typeof core.catalog === "undefined") {
|
||||||
|
@ -31,6 +39,13 @@ import("/js/core.js").then(() =>
|
||||||
*/
|
*/
|
||||||
static categories = [];
|
static categories = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registry of filters (instead of cookies)
|
||||||
|
*/
|
||||||
|
static filters = new Map([
|
||||||
|
['brand', null]
|
||||||
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select a category (interface)
|
* Select a category (interface)
|
||||||
*
|
*
|
||||||
|
@ -453,62 +468,62 @@ import("/js/core.js").then(() =>
|
||||||
const images = document.createElement("div");
|
const images = document.createElement("div");
|
||||||
images.classList.add("images", "unselectable");
|
images.classList.add("images", "unselectable");
|
||||||
|
|
||||||
for (const uri of json.product.images) {
|
|
||||||
const image = document.createElement("img");
|
|
||||||
image.setAttribute("src", uri);
|
|
||||||
image.setAttribute("ondragstart", "return false;");
|
|
||||||
|
|
||||||
const button = core.telegram.api.isVisible;
|
const button = core.telegram.api.isVisible;
|
||||||
|
|
||||||
const open = (event) => {
|
const _open = (event) => {
|
||||||
if (event.target === from) {
|
if (event.target === from) {
|
||||||
if (typeof images.hotline === "object") {
|
if (typeof images.hotline === "object") {
|
||||||
if (images.hotline.moving) return;
|
if (images.hotline.moving) return;
|
||||||
images.hotline.stop();
|
images.hotline.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
image.classList.add("extend");
|
images.classList.add("extend");
|
||||||
|
|
||||||
if (button) core.telegram.api.MainButton.hide();
|
if (button) core.telegram.api.MainButton.hide();
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
image.addEventListener("click", close);
|
images.addEventListener("click", _close);
|
||||||
image.addEventListener("touch", close);
|
images.addEventListener("touch", _close);
|
||||||
}, 300);
|
}, 300);
|
||||||
image.removeEventListener("mouseup", open);
|
images.removeEventListener("mouseup", _open);
|
||||||
image.removeEventListener("touchend", open);
|
images.removeEventListener("touchend", _open);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const close = () => {
|
const _close = () => {
|
||||||
if (typeof images.hotline === "object") {
|
if (typeof images.hotline === "object") {
|
||||||
images.hotline.start();
|
images.hotline.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
image.classList.remove("extend");
|
images.classList.remove("extend");
|
||||||
|
|
||||||
if (button) core.telegram.api.MainButton.show();
|
if (button) core.telegram.api.MainButton.show();
|
||||||
|
|
||||||
image.removeEventListener("click", close);
|
images.removeEventListener("click", _close);
|
||||||
image.removeEventListener("touch", close);
|
images.removeEventListener("touch", _close);
|
||||||
image.addEventListener("mousedown", start);
|
images.addEventListener("mousedown", _start);
|
||||||
image.addEventListener("touchstart", start);
|
images.addEventListener("touchstart", _start);
|
||||||
};
|
};
|
||||||
|
|
||||||
const start = (event) => {
|
const _start = (event) => {
|
||||||
if (
|
if (
|
||||||
event.type === "touchstart" ||
|
event.type === "touchstart" ||
|
||||||
event.button === 0
|
event.button === 0
|
||||||
) {
|
) {
|
||||||
image.removeEventListener("mousedown", start);
|
images.removeEventListener("mousedown", _start);
|
||||||
image.removeEventListener("touchstart", start);
|
images.removeEventListener("touchstart", _start);
|
||||||
image.addEventListener("mouseup", open);
|
images.addEventListener("mouseup", _open);
|
||||||
image.addEventListener("touchend", open);
|
images.addEventListener("touchend", _open);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
image.addEventListener("mousedown", start);
|
images.addEventListener("mousedown", _start);
|
||||||
image.addEventListener("touchstart", start);
|
images.addEventListener("touchstart", _start);
|
||||||
|
|
||||||
|
for (const uri of json.product.images) {
|
||||||
|
const image = document.createElement("img");
|
||||||
|
image.setAttribute("src", uri);
|
||||||
|
image.setAttribute("ondragstart", "return false;");
|
||||||
|
|
||||||
images.append(image);
|
images.append(image);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,10 @@ import("/js/core.js").then(() => {
|
||||||
initialization();
|
initialization();
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
const timeout = setTimeout(() => clearInterval(dependencies), 5000);
|
const timeout = setTimeout(() => {
|
||||||
|
clearInterval(dependencies);
|
||||||
|
initialization();
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
function initialization() {
|
function initialization() {
|
||||||
if (typeof core.damper === "undefined") {
|
if (typeof core.damper === "undefined") {
|
||||||
|
|
|
@ -9,7 +9,10 @@ import("/js/core.js").then(() => {
|
||||||
initialization();
|
initialization();
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
const timeout = setTimeout(() => clearInterval(dependencies), 5000);
|
const timeout = setTimeout(() => {
|
||||||
|
clearInterval(dependencies);
|
||||||
|
initialization();
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
function initialization() {
|
function initialization() {
|
||||||
if (typeof core.hotline === "undefined") {
|
if (typeof core.hotline === "undefined") {
|
||||||
|
|
|
@ -4,14 +4,19 @@
|
||||||
import("/js/core.js").then(() =>
|
import("/js/core.js").then(() =>
|
||||||
import("/js/damper.js").then(() => {
|
import("/js/damper.js").then(() => {
|
||||||
const dependencies = setInterval(() => {
|
const dependencies = setInterval(() => {
|
||||||
if (typeof core === "function" &&
|
if (
|
||||||
typeof core.damper === "function") {
|
typeof core === "function" &&
|
||||||
|
typeof core.damper === "function"
|
||||||
|
) {
|
||||||
clearInterval(dependencies);
|
clearInterval(dependencies);
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
initialization();
|
initialization();
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
const timeout = setTimeout(() => clearInterval(dependencies), 5000);
|
const timeout = setTimeout(() => {
|
||||||
|
clearInterval(dependencies);
|
||||||
|
initialization();
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
function initialization() {
|
function initialization() {
|
||||||
if (typeof core.session === "undefined") {
|
if (typeof core.session === "undefined") {
|
||||||
|
|
|
@ -13,7 +13,10 @@ import("/js/core.js").then(() =>
|
||||||
initialization();
|
initialization();
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
const timeout = setTimeout(() => clearInterval(dependencies), 5000);
|
const timeout = setTimeout(() => {
|
||||||
|
clearInterval(dependencies);
|
||||||
|
initialization();
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
function initialization() {
|
function initialization() {
|
||||||
if (typeof core.telegram === "undefined") {
|
if (typeof core.telegram === "undefined") {
|
||||||
|
|
|
@ -7,16 +7,16 @@ namespace mirzaev\arming_bot;
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\controllers\core as controller,
|
use mirzaev\arming_bot\controllers\core as controller,
|
||||||
mirzaev\arming_bot\models\core as model,
|
mirzaev\arming_bot\models\core as model,
|
||||||
mirzaev\arming_bot\models\chat;
|
mirzaev\arming_bot\models\telegram;
|
||||||
|
|
||||||
// Фреймворк Telegram
|
// Фреймворк Telegram
|
||||||
use Zanzara\Zanzara,
|
use Zanzara\Zanzara,
|
||||||
Zanzara\Context,
|
Zanzara\Context,
|
||||||
Zanzara\Config;
|
Zanzara\Config;
|
||||||
|
|
||||||
/* ini_set('error_reporting', E_ALL);
|
ini_set('error_reporting', E_ALL);
|
||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 1);
|
||||||
ini_set('display_startup_errors', 1); */
|
ini_set('display_startup_errors', 1);
|
||||||
|
|
||||||
// Версия робота
|
// Версия робота
|
||||||
define('ROBOT_VERSION', '1.0.0');
|
define('ROBOT_VERSION', '1.0.0');
|
||||||
|
@ -62,27 +62,27 @@ $bot = new Zanzara(KEY, $config);
|
||||||
var_dump($ctx->getEffectiveUser() );
|
var_dump($ctx->getEffectiveUser() );
|
||||||
}); */
|
}); */
|
||||||
|
|
||||||
$bot->onCommand('start', fn($ctx) => chat::start($ctx));
|
$bot->onCommand('start', fn($ctx) => telegram::start($ctx));
|
||||||
$bot->onCommand('contacts', fn($ctx) => chat::contacts($ctx));
|
$bot->onCommand('contacts', fn($ctx) => telegram::contacts($ctx));
|
||||||
$bot->onCommand('company', fn($ctx) => chat::company($ctx));
|
$bot->onCommand('company', fn($ctx) => telegram::company($ctx));
|
||||||
$bot->onCommand('community', fn($ctx) => chat::community($ctx));
|
$bot->onCommand('community', fn($ctx) => telegram::community($ctx));
|
||||||
$bot->onCommand('settings', fn($ctx) => chat::settings($ctx));
|
$bot->onCommand('settings', fn($ctx) => telegram::settings($ctx));
|
||||||
|
|
||||||
$bot->onText('💬 Контакты', fn($ctx) => chat::contacts($ctx));
|
$bot->onText('💬 Контакты', fn($ctx) => telegram::contacts($ctx));
|
||||||
$bot->onText('🏛️ О компании', fn($ctx) => chat::company($ctx));
|
$bot->onText('🏛️ О компании', fn($ctx) => telegram::company($ctx));
|
||||||
$bot->onText('🎯 Сообщество', fn($ctx) => chat::community($ctx));
|
$bot->onText('🎯 Сообщество', fn($ctx) => telegram::community($ctx));
|
||||||
$bot->onText('⚙️ Настройки', fn($ctx) => chat::settings($ctx));
|
$bot->onText('⚙️ Настройки', fn($ctx) => telegram::settings($ctx));
|
||||||
|
|
||||||
$bot->onCbQueryData(['mail'], fn($ctx) => chat::_mail($ctx));
|
$bot->onCbQueryData(['mail'], fn($ctx) => telegram::_mail($ctx));
|
||||||
$bot->onCbQueryData(['import_request'], fn($ctx) => chat::import_request($ctx));
|
$bot->onCbQueryData(['import_request'], fn($ctx) => telegram::import_request($ctx));
|
||||||
$bot->onCbQueryData(['tuning'], fn($ctx) => chat::tuning($ctx));
|
$bot->onCbQueryData(['tuning'], fn($ctx) => telegram::tuning($ctx));
|
||||||
$bot->onCbQueryData(['brands'], fn($ctx) => chat::brands($ctx));
|
$bot->onCbQueryData(['brands'], fn($ctx) => telegram::brands($ctx));
|
||||||
|
|
||||||
// Инициализация middleware с обработкой аккаунта
|
// Инициализация middleware с обработкой аккаунта
|
||||||
$bot->middleware([chat::class, "account"]);
|
$bot->middleware([telegram::class, "account"]);
|
||||||
|
|
||||||
// Инициализация middleware с обработкой технических работ разных уровней
|
// Инициализация middleware с обработкой технических работ разных уровней
|
||||||
$bot->middleware([chat::class, "suspension"]);
|
$bot->middleware([telegram::class, "suspension"]);
|
||||||
|
|
||||||
// Запуск чат-робота
|
// Запуск чат-робота
|
||||||
$bot->run();
|
$bot->run();
|
||||||
|
|
|
@ -8,21 +8,60 @@ main>section[data-section="catalog"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[type="button"] {
|
main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[type="button"] {
|
||||||
|
position: relative;
|
||||||
height: 23px;
|
height: 23px;
|
||||||
padding: 8px 16px;
|
padding: unset;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
overflow: hidden;
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
color: var(--tg-theme-button-text-color);
|
color: var(--tg-theme-button-text-color);
|
||||||
background-color: var(--tg-theme-button-color);
|
background-color: var(--tg-theme-button-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
main>section[data-section="catalog"][data-catalog-type="categories"]:last-child {
|
main>section[data-section="catalog"][data-catalog-type="categories"]:last-child {
|
||||||
/* margin-bottom: unset; */
|
/* margin-bottom: unset; */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[type="button"]:has(>img) {
|
||||||
|
height: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[type="button"]>img {
|
||||||
|
position: absolute;
|
||||||
|
left: -5%;
|
||||||
|
top: -5%;
|
||||||
|
width: 110%;
|
||||||
|
height: 110%;
|
||||||
|
object-fit: cover;
|
||||||
|
filter: blur(1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[type="button"]:hover>img {
|
||||||
|
filter: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section[data-section="catalog"][data-catalog-type="categories"]>a.category[type="button"]>p {
|
||||||
|
z-index: 100;
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
main>section[data-section="catalog"][data-catalog-type="products"] {
|
main>section[data-section="catalog"][data-catalog-type="products"] {
|
||||||
--column: calc((100% - var(--gap)) / 2);
|
--column: calc((100% - var(--gap)) / 2);
|
||||||
width: var(--width);
|
width: var(--width);
|
||||||
|
@ -120,3 +159,21 @@ main>section[data-section="cart"]>i.icon.shopping.cart {
|
||||||
top: -1px;
|
top: -1px;
|
||||||
color: var(--tg-theme-button-text-color);
|
color: var(--tg-theme-button-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main>section[data-section="filters"] {
|
||||||
|
--diameter: 4rem;
|
||||||
|
z-index: 999;
|
||||||
|
right: 5vw;
|
||||||
|
bottom: 5vw;
|
||||||
|
position: fixed;
|
||||||
|
width: var(--diameter);
|
||||||
|
height: var(--diameter);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 100%;
|
||||||
|
background-color: var(--tg-theme-button-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section[data-section="filters"][data-filter="brand"] {}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
@charset "UTF-8";
|
||||||
|
|
||||||
|
i.icon.hashtag {
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
transform: scale(1);
|
||||||
|
width: 8px;
|
||||||
|
height: 16px;
|
||||||
|
border-left: 2px solid;
|
||||||
|
border-right: 2px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.icon.hashtag::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: absolute;
|
||||||
|
width: 16px;
|
||||||
|
height: 8px;
|
||||||
|
border-top: 2px solid;
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
left: -6px;
|
||||||
|
top: 4px;
|
||||||
|
}
|
||||||
|
|
|
@ -50,6 +50,21 @@ section#window>div.card>div.images {
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section#window>div.card>div.images.extend {
|
||||||
|
z-index: 9999999;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
margin: unset !important;
|
||||||
|
position: absolute;
|
||||||
|
width: 100vw;
|
||||||
|
max-width: unset;
|
||||||
|
height: 100vh;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: unset;
|
||||||
|
transition: 0s;
|
||||||
|
cursor: zoom-out;
|
||||||
|
}
|
||||||
|
|
||||||
section#window>div.card>div.images>img {
|
section#window>div.card>div.images>img {
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
width: 10rem;
|
width: 10rem;
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
!example.xlsx
|
|
||||||
import.xlsx
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
!.gitignore
|
||||||
|
*
|
|
@ -0,0 +1,2 @@
|
||||||
|
!.gitignore
|
||||||
|
*
|
|
@ -0,0 +1,2 @@
|
||||||
|
!.gitignore
|
||||||
|
*
|
|
@ -3,8 +3,10 @@
|
||||||
data-catalog-level="{{ level ?? 0 }}">
|
data-catalog-level="{{ level ?? 0 }}">
|
||||||
{% for category in categories %}
|
{% for category in categories %}
|
||||||
<a id="{{ category.getId() }}" class="category" type="button" onclick="return core.catalog.category(this);"
|
<a id="{{ category.getId() }}" class="category" type="button" onclick="return core.catalog.category(this);"
|
||||||
data-category-name="{{ category.name }}">{{
|
data-category-identifier="{{ category.identifier }}">
|
||||||
category.label.ru }}</a>
|
<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>
|
||||||
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</section>
|
</section>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% if filters is not empty %}
|
||||||
|
<section data-section="filters" data-filter="brand">
|
||||||
|
{% for brand in filters.brands %}
|
||||||
|
<input class="menu" name="brand" type="radio" id="brand_{{ loop.index }}" checked>
|
||||||
|
<label for="brand_{{ loop.index }}" class="menu option">{{ brand }}</label>
|
||||||
|
{% endfor %}
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
|
@ -3,7 +3,7 @@
|
||||||
~ product.dimensions.z ~ ' ' ~ product.weight ~ 'г' %}
|
~ product.dimensions.z ~ ' ' ~ product.weight ~ 'г' %}
|
||||||
<article id="{{ product.getId() }}" class="product unselectable">
|
<article id="{{ product.getId() }}" class="product unselectable">
|
||||||
<a onclick="core.catalog.product({{ product.getKey() }})">
|
<a onclick="core.catalog.product({{ product.getKey() }})">
|
||||||
<img src="/images/{{ product.getKey() }}/1.jpg" alt="{{ product.title.ru }}" ondrugstart="return false;">
|
<img src="{{ product.images.0.storage }}" alt="{{ product.title.ru }}" ondrugstart="return false;">
|
||||||
<p class="title" title="{{ product.title.ru }}">
|
<p class="title" title="{{ product.title.ru }}">
|
||||||
{{ title | length > 45 ? title | slice(0, 45) ~ '...' : title }}
|
{{ title | length > 45 ? title | slice(0, 45) ~ '...' : title }}
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
{% include "/themes/default/catalog/elements/categories.html" %}
|
{% include "/themes/default/catalog/elements/categories.html" %}
|
||||||
{% include "/themes/default/catalog/elements/products/2columns.html" %}
|
{% include "/themes/default/catalog/elements/products/2columns.html" %}
|
||||||
<!-- {% include "/themes/default/catalog/elements/cart.html" %} -->
|
<!-- {% include "/themes/default/catalog/elements/cart.html" %} -->
|
||||||
|
{% include "/themes/default/catalog/elements/filters.html" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
|
|
Loading…
Reference in New Issue