diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..248ba7b3e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea +.DS_Store +app/.env +app/vendor +app/logs \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 000000000..9e4acd7cb --- /dev/null +++ b/Readme.md @@ -0,0 +1,29 @@ +**Как использовать** +\ +\ +Везде использовать POST + +Для того чтобы добавить event, надо отправить запрос с JSON данными +```json +{ + "request_type": "add", + "priority": 4000, + "conditions": ["param1=1", "param2=2", "param3=3"], + "event": "event_4" +} +``` + +Для поиск нужно отправить запрос с JSON-данными +```json +{ + "request_type": "search", + "conditions": ["param1=1", "param2=2", "param3=3"], +} +``` + +Для удаления нужно отправить запрос с JSON-данными +```json +{ + "type_request": "delete" +} +``` diff --git a/app/.env.example b/app/.env.example new file mode 100644 index 000000000..c740c872a --- /dev/null +++ b/app/.env.example @@ -0,0 +1,5 @@ +STORAGE=redis +REDIS_HOST=redis +REDIS_PORT=6379 + +LOG_PATH=../logs/app.log diff --git a/app/bootstrap/bootstrap.php b/app/bootstrap/bootstrap.php new file mode 100644 index 000000000..71ae83df1 --- /dev/null +++ b/app/bootstrap/bootstrap.php @@ -0,0 +1,6 @@ +load(); diff --git a/app/composer.json b/app/composer.json new file mode 100644 index 000000000..96b6aad50 --- /dev/null +++ b/app/composer.json @@ -0,0 +1,24 @@ +{ + "name": "rsm/app", + "description": "hw-otus", + "type": "project", + "authors": [ + { + "name": "yessaliyev", + "email": "40271311+yessaliyev@users.noreply.github.com" + } + ], + "minimum-stability": "dev", + "require": { + "vlucas/phpdotenv": "^5.2@dev", + "monolog/monolog": "2.x-dev", + "ext-redis": "*", + "ext-json": "*", + "rakit/validation": "dev-master" + }, + "autoload": { + "psr-4": { + "Otus\\": "src/hw" + } + } +} diff --git a/app/composer.lock b/app/composer.lock new file mode 100644 index 000000000..627cdf673 --- /dev/null +++ b/app/composer.lock @@ -0,0 +1,679 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "73c96e62910c242ce496c53ce90c698a", + "packages": [ + { + "name": "graham-campbell/result-type", + "version": "1.0.x-dev", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "cce288e91826d6d33d76b57f1ad4bdc3f3a8c1d6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/cce288e91826d6d33d76b57f1ad4bdc3f3a8c1d6", + "reference": "cce288e91826d6d33d76b57f1ad4bdc3f3a8c1d6", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "phpoption/phpoption": "^1.7.3" + }, + "require-dev": { + "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.7" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "graham@alt-three.com" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/1.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2021-01-25T20:12:13+00:00" + }, + { + "name": "monolog/monolog", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "c1971982c3b792e488726468046b1ef977934c6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c1971982c3b792e488726468046b1ef977934c6a", + "reference": "c1971982c3b792e488726468046b1ef977934c6a", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "psr/log": "^1.0.1" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7", + "graylog2/gelf-php": "^1.4.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpspec/prophecy": "^1.6.1", + "phpstan/phpstan": "^0.12.59", + "phpunit/phpunit": "^8.5", + "predis/predis": "^1.1", + "rollbar/rollbar": "^1.3", + "ruflin/elastica": ">=0.90 <7.0.1", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/main" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2021-02-09T13:27:42+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525", + "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.7.5" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2020-07-20T17:29:33+00:00" + }, + { + "name": "psr/log", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "dd738d0b4491f32725492cf345f6b501f5922fec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/dd738d0b4491f32725492cf345f6b501f5922fec", + "reference": "dd738d0b4491f32725492cf345f6b501f5922fec", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/master" + }, + "time": "2020-09-18T06:44:51+00:00" + }, + { + "name": "rakit/validation", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/rakit/validation.git", + "reference": "ff003a35cdf5030a5f2482299f4c93f344a35b29" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rakit/validation/zipball/ff003a35cdf5030a5f2482299f4c93f344a35b29", + "reference": "ff003a35cdf5030a5f2482299f4c93f344a35b29", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=7.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^6.5", + "squizlabs/php_codesniffer": "^3" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "Rakit\\Validation\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Muhammad Syifa", + "email": "emsifa@gmail.com" + } + ], + "description": "PHP Laravel like standalone validation library", + "support": { + "issues": "https://github.com/rakit/validation/issues", + "source": "https://github.com/rakit/validation/tree/master" + }, + "time": "2020-08-27T05:07:01+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-07T16:49:33+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-22T09:19:47+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-07T16:49:33+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "b3eac5c7ac896e52deab4a99068e3f4ab12d9e56" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/b3eac5c7ac896e52deab4a99068e3f4ab12d9e56", + "reference": "b3eac5c7ac896e52deab4a99068e3f4ab12d9e56", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.0.1", + "php": "^7.1.3 || ^8.0", + "phpoption/phpoption": "^1.7.4", + "symfony/polyfill-ctype": "^1.17", + "symfony/polyfill-mbstring": "^1.17", + "symfony/polyfill-php80": "^1.17" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "ext-filter": "*", + "phpunit/phpunit": "^7.5.20 || ^8.5.14 || ^9.5.1" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.3-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "homepage": "https://gjcampbell.co.uk/" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://vancelucas.com/" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.3.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2021-01-20T15:23:13+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": { + "vlucas/phpdotenv": 20, + "monolog/monolog": 20, + "rakit/validation": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "ext-redis": "*", + "ext-json": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/app/public/index.php b/app/public/index.php new file mode 100644 index 000000000..b3ef90e26 --- /dev/null +++ b/app/public/index.php @@ -0,0 +1,13 @@ +run(); +} catch (\Exception $e) { + View::showMessage($e->getMessage()); +} diff --git a/app/src/hw/App.php b/app/src/hw/App.php new file mode 100644 index 000000000..a393e00d1 --- /dev/null +++ b/app/src/hw/App.php @@ -0,0 +1,34 @@ +validate(); + $this->data = $validator->getValidatedData(); + + $this->storage = $this->getStorage(); + } + + public function run() + { + $event = EventProcessFactory::getProcess($this->data); + $event->process($this->storage); + } + + private function getStorage(): StorageInterface + { + return StorageFactory::create(); + } +} diff --git a/app/src/hw/DTO/EventDTO.php b/app/src/hw/DTO/EventDTO.php new file mode 100644 index 000000000..28594cf0a --- /dev/null +++ b/app/src/hw/DTO/EventDTO.php @@ -0,0 +1,56 @@ +priority; + } + + public function setPriority(int $priority): void + { + $this->priority = $priority; + } + + public function getId(): int + { + return $this->id; + } + + public function setId($id): void + { + $this->id = $id; + } + + public function getEvent(): string + { + return $this->event; + } + + public function setEvent(string $event): void + { + $this->event = $event; + } + + public function getConditions(): array + { + return $this->conditions; + } + + public function setConditions(array $conditions): void + { + $this->conditions = $conditions; + } + + public function toArray(): array + { + return get_object_vars($this); + } +} diff --git a/app/src/hw/DTO/UserRequestDTO.php b/app/src/hw/DTO/UserRequestDTO.php new file mode 100644 index 000000000..d65dbd0e9 --- /dev/null +++ b/app/src/hw/DTO/UserRequestDTO.php @@ -0,0 +1,19 @@ +conditions; + } + + public function setConditions(array $conditions): void + { + $this->conditions = $conditions; + } + +} \ No newline at end of file diff --git a/app/src/hw/Exceptions/AppException.php b/app/src/hw/Exceptions/AppException.php new file mode 100644 index 000000000..8da773fbd --- /dev/null +++ b/app/src/hw/Exceptions/AppException.php @@ -0,0 +1,17 @@ +pushHandler(new StreamHandler($_ENV['LOG_PATH'])); + $log->addRecord($level, $message, $context); + } +} \ No newline at end of file diff --git a/app/src/hw/Processes/EventCreator.php b/app/src/hw/Processes/EventCreator.php new file mode 100644 index 000000000..c226e2d1d --- /dev/null +++ b/app/src/hw/Processes/EventCreator.php @@ -0,0 +1,36 @@ +createEvent($data); + } + + public function process(StorageInterface $storage) + { + $storage->save($this->event); + View::showMessage("event was added"); + } + + private function createEvent($data) + { + $event = new EventDTO(); + $event->setId(time()); + $event->setEvent($data['event']); + $event->setConditions($data['conditions']); + $event->setPriority($data['priority']); + + $this->event = $event; + } +} \ No newline at end of file diff --git a/app/src/hw/Processes/EventDeleter.php b/app/src/hw/Processes/EventDeleter.php new file mode 100644 index 000000000..55dd0cbfc --- /dev/null +++ b/app/src/hw/Processes/EventDeleter.php @@ -0,0 +1,17 @@ +delete(); + View::showMessage('all events have been deleted'); + } +} \ No newline at end of file diff --git a/app/src/hw/Processes/EventProcessFactory.php b/app/src/hw/Processes/EventProcessFactory.php new file mode 100644 index 000000000..7701924ba --- /dev/null +++ b/app/src/hw/Processes/EventProcessFactory.php @@ -0,0 +1,25 @@ +createUserRequestDTO($data); + } + + public function process(StorageInterface $storage) + { + /** @var EventDTO $result */ + $result = $storage->find($this->requestDTO); + View::showResult($result->toArray()); + } + + private function createUserRequestDTO(array $data) + { + $requestDTO = new UserRequestDTO(); + $requestDTO->setConditions($data['conditions']); + + $this->requestDTO = $requestDTO; + } + +} \ No newline at end of file diff --git a/app/src/hw/Storage/RedisDAO.php b/app/src/hw/Storage/RedisDAO.php new file mode 100644 index 000000000..39882aa40 --- /dev/null +++ b/app/src/hw/Storage/RedisDAO.php @@ -0,0 +1,168 @@ +redis = new Redis(); + $this->redis->connect($_ENV['REDIS_HOST'], $_ENV['REDIS_PORT']); + } + + public function find(UserRequestDTO $userRequestDTO): ?EventDTO + { + $sets = $this->findEvents($userRequestDTO->getConditions()); + $eventIDs = $this->findSuitableEvents($userRequestDTO->getConditions(), $sets); + $raw = $this->getEventMaxPriority($eventIDs); + $eventData = $this->redis->get($this->generateKeyEvent($raw['event_id'])); + $conditions = $this->redis->sMembers($this->generateKeyConditions($raw['event_id'])); + + $eventDTO = new EventDTO(); + $eventDTO->setId($raw['event_id']); + $eventDTO->setConditions($conditions); + $eventDTO->setPriority($raw['priority']); + $eventDTO->setEvent($eventData); + + return $eventDTO; + } + + public function save(EventDTO $event) + { + $key = $this->generateKey($event->getId()); + + $partOne = $this->redis->multi() + ->zAdd($this->generatePriority(), [], $event->getPriority(), $key) + ->set($this->generateKeyEvent($event->getId()), $event->getEvent()) + ->exec(); + + $this->redis->multi(); + + foreach ($event->getConditions() as $condition) { + $this->redis->sAdd($this->generateKeyConditions($event->getId()), $condition); + $this->redis->sAdd($this->generateHelperConditions($condition), $key . ':conditions'); + } + + $partTwo = $this->redis->exec(); + return array_merge($partOne, $partTwo); + } + + public function delete(): bool + { + return $this->redis->del($this->redis->keys(self::KEY . '*')); + } + + private function findEvents(array $conditions): array + { + $sets = []; + foreach ($conditions as $item) { + $item = $this->generateHelperConditions($item); + $buf = $this->redis->sMembers($item); + + foreach ($buf as $keyConditions) { + $sets[$keyConditions] = [ + 'number' => $this->redis->sCard($keyConditions), + 'suitable_number' => 0 + ]; + } + } + + if (empty($sets)) { + throw new AppException('No sets found'); + } + + return $sets; + } + + private function findSuitableEvents(array $conditions, array $sets): array + { + foreach ($sets as $keyConditions => &$item) { + foreach ($conditions as $condition) { + $result = $this->redis->sIsMember($keyConditions, $condition); + if ($result) { + $item['suitable_number']++; + } + } + } + + $eventIDs = []; + foreach ($sets as $keyConditions => $item) { + if ($item['number'] == $item['suitable_number']) { + $eventID = $this->getEventIDFromKeyConditions($keyConditions); + $key = $this->generateKey($eventID); + $eventIDs[$key] = [ + 'priority' => $this->redis->zScore($this->generatePriority(), $key), + 'event_id' => $eventID + ]; + } + } + + return $eventIDs; + } + + private function getEventMaxPriority(array $eventIDs): array + { + $scores = array_column($eventIDs, 'priority'); + $maxPriority = max($scores); + foreach ($eventIDs as $item) { + if ($item['priority'] == $maxPriority) { + $eventID = $item['event_id']; + break; + } + } + + return ['priority' => $maxPriority, 'event_id' => $eventID]; + } + + private function getEventIDFromKeyConditions(string $keyConditions): string + { + $result = explode(':', $keyConditions); + if (empty($result[1])) { + throw new AppException('Redis is not structured correctly.'); + } + return $result[1]; + } + + private function generateKey($id) + { + return self::KEY . $id; + } + + private function generateKeyConditions(string $id): string + { + return $this->generateKey($id) . ':conditions'; + } + + private function generateKeyEvent(string $id): string + { + return $this->generateKey($id) . ':event'; + } + + private function generateHelperConditions(string $item): string + { + return self::KEY . $item; + } + + private function generatePriority(): string + { + return self::KEY . ':priority'; + } + + public function __destruct() + { + $this->redis->close(); + } + + +} \ No newline at end of file diff --git a/app/src/hw/Storage/StorageFactory.php b/app/src/hw/Storage/StorageFactory.php new file mode 100644 index 000000000..f6840f266 --- /dev/null +++ b/app/src/hw/Storage/StorageFactory.php @@ -0,0 +1,24 @@ +validator = new Validator(); + + $json = file_get_contents('php://input'); + + if (empty($json)) { + throw new AppException('body is empty', Logger::ERROR); + } + + $this->data = json_decode($json, true, 512, JSON_THROW_ON_ERROR); + } + + /** + * @throws AppException + */ + public function validate() + { + switch ($this->data['request_type']) { + case self::SEARCH_REQUEST: + $this->validateSearch(); + break; + case self::ADD_REQUEST: + $this->validateAdd(); + break; + case self::DELETE_REQUEST: + break; + default: + throw new AppException("Invalid request method", Logger::ERROR); + } + } + + private function validateSearch() + { + $validation = $this->validator->validate($this->data,[ + 'conditions' => 'required|array' + ]); + + if ($validation->fails()) { + throw new AppException('Validation error, reason: ' . json_encode($validation->errors()->firstOfAll()), Logger::ERROR); + } + + return true; + } + + private function validateAdd() + { + $validation = $this->validator->validate($this->data, [ + 'event' => 'required', + 'conditions' => 'required|array', + 'priority' => 'required|numeric' + ]); + + if ($validation->fails()) { + throw new AppException('Validation error, reason: ' . json_encode($validation->errors()->firstOfAll()), Logger::ERROR); + } + + return true; + } + + public function getValidatedData() + { + return $this->data; + } +} diff --git a/app/src/hw/View.php b/app/src/hw/View.php new file mode 100644 index 000000000..917c9386c --- /dev/null +++ b/app/src/hw/View.php @@ -0,0 +1,20 @@ +