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..61108a03e --- /dev/null +++ b/Readme.md @@ -0,0 +1,19 @@ +**Как использовать** + +1)зайти в контейнер php-fpm через команду docker-compose exec php-fpm bash +2)зайти в директорию public +3)запустить скрипт через команду php index.php + +index.php принимает параметры + +- analyze (id youtube каналов через запятую) +- statistics (id канала для получения статистики) +- top_n (получить топ n каналов по соотношению likes/dislikes); + +Пример: + +php index.php analyze UCMcDsSeqS531-HKz6GiJgtA,UC2QJf0YXCH57FR588wQIaSg + +php index.php statistics UCMcDsSeqS531-HKz6GiJgtA + +php index.php ton_n 3 diff --git a/app/.env.example b/app/.env.example new file mode 100644 index 000000000..9a84fb11e --- /dev/null +++ b/app/.env.example @@ -0,0 +1,17 @@ +YOUTUBE_API_KEY=API_KEY +YOUTUBE_CLIENT_ID=CLIENT_ID +YOUTUBE_CLIENT_SECRET=CLIENT_SECRET + +#no_sql can be => ElasticSearch, MongoDB +NO_SQL_DB='ElasticSearch' + +ELASTIC_SEARCH_HOST=elastic-search +ELASTIC_SEARCH_PORT=9200 + +VIDEOPLATFORM=youtube + +MONGODB_HOST=mongo-db +MONGODB_PORT=27017 +MONGODB_USERNAME=root +MONGODB_PASSWORD=root +MONGODB_DATABASE=otus \ No newline at end of file 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..ba4bfaaae --- /dev/null +++ b/app/composer.json @@ -0,0 +1,25 @@ +{ + "name": "rsm/app", + "description": "hw-otus", + "type": "project", + "authors": [ + { + "name": "yessaliyev", + "email": "40271311+yessaliyev@users.noreply.github.com" + } + ], + "minimum-stability": "dev", + "require": { + "google/apiclient": "^2.0", + "vlucas/phpdotenv": "^5.2@dev", + "guzzlehttp/guzzle": "^7.1@dev", + "elasticsearch/elasticsearch": "dev-master", + "mongodb/mongodb": "1.9.x-dev", + "monolog/monolog": "2.x-dev" + }, + "autoload": { + "psr-4": { + "VideoPlatform\\": "src/hw" + } + } +} diff --git a/app/composer.lock b/app/composer.lock new file mode 100644 index 000000000..92b730fcd --- /dev/null +++ b/app/composer.lock @@ -0,0 +1,1854 @@ +{ + "_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": "c34491169215ad26f5054e992b7f2ff8", + "packages": [ + { + "name": "composer/package-versions-deprecated", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/composer/package-versions-deprecated.git", + "reference": "f921205948ab93bb19f86327c793a81edb62f236" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/f921205948ab93bb19f86327c793a81edb62f236", + "reference": "f921205948ab93bb19f86327c793a81edb62f236", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1.0 || ^2.0", + "php": "^7 || ^8" + }, + "replace": { + "ocramius/package-versions": "1.11.99" + }, + "require-dev": { + "composer/composer": "^1.9.3 || ^2.0@dev", + "ext-zip": "^1.13", + "phpunit/phpunit": "^6.5 || ^7" + }, + "default-branch": true, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "support": { + "issues": "https://github.com/composer/package-versions-deprecated/issues", + "source": "https://github.com/composer/package-versions-deprecated/tree/master" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-12-27T20:11:05+00:00" + }, + { + "name": "elasticsearch/elasticsearch", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/elastic/elasticsearch-php.git", + "reference": "0d80e531bd3d321bd1011127e917e771002c76ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/elastic/elasticsearch-php/zipball/0d80e531bd3d321bd1011127e917e771002c76ac", + "reference": "0d80e531bd3d321bd1011127e917e771002c76ac", + "shasum": "" + }, + "require": { + "ext-json": ">=1.3.7", + "ezimuel/ringphp": "^1.1.2", + "php": "^7.1", + "psr/log": "~1.0" + }, + "require-dev": { + "cpliakas/git-wrapper": "~2.0", + "doctrine/inflector": "^1.3", + "mockery/mockery": "^1.2", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^7.5", + "squizlabs/php_codesniffer": "^3.4", + "symfony/finder": "~4.0", + "symfony/yaml": "~4.0" + }, + "suggest": { + "ext-curl": "*", + "monolog/monolog": "Allows for client-level logging and tracing" + }, + "type": "library", + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Elasticsearch\\": "src/Elasticsearch/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Zachary Tong" + }, + { + "name": "Enrico Zimuel" + } + ], + "description": "PHP Client for Elasticsearch", + "keywords": [ + "client", + "elasticsearch", + "search" + ], + "time": "2020-12-17T22:07:25+00:00" + }, + { + "name": "ezimuel/guzzlestreams", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/ezimuel/guzzlestreams.git", + "reference": "abe3791d231167f14eb80d413420d1eab91163a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezimuel/guzzlestreams/zipball/abe3791d231167f14eb80d413420d1eab91163a8", + "reference": "abe3791d231167f14eb80d413420d1eab91163a8", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Fork of guzzle/streams (abandoned) to be used with elasticsearch-php", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "stream" + ], + "time": "2020-02-14T23:11:50+00:00" + }, + { + "name": "ezimuel/ringphp", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/ezimuel/ringphp.git", + "reference": "0b78f89d8e0bb9e380046c31adfa40347e9f663b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezimuel/ringphp/zipball/0b78f89d8e0bb9e380046c31adfa40347e9f663b", + "reference": "0b78f89d8e0bb9e380046c31adfa40347e9f663b", + "shasum": "" + }, + "require": { + "ezimuel/guzzlestreams": "^3.0.1", + "php": ">=5.4.0", + "react/promise": "~2.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "ext-curl": "Guzzle will use specific adapters if cURL is present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Ring\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Fork of guzzle/RingPHP (abandoned) to be used with elasticsearch-php", + "time": "2020-02-14T23:51:21+00:00" + }, + { + "name": "firebase/php-jwt", + "version": "v5.2.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "feb0e820b8436873675fd3aca04f3728eb2185cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/feb0e820b8436873675fd3aca04f3728eb2185cb", + "reference": "feb0e820b8436873675fd3aca04f3728eb2185cb", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": ">=4.8 <=9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "time": "2020-03-25T18:49:23+00:00" + }, + { + "name": "google/apiclient", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-api-php-client.git", + "reference": "e0753f9fb61e514b821108fcde665a10e1cce51c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/e0753f9fb61e514b821108fcde665a10e1cce51c", + "reference": "e0753f9fb61e514b821108fcde665a10e1cce51c", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "~2.0||~3.0||~4.0||~5.0", + "google/apiclient-services": "~0.13", + "google/auth": "^1.10", + "guzzlehttp/guzzle": "~5.3.3||~6.0||~7.0", + "guzzlehttp/psr7": "^1.2", + "monolog/monolog": "^1.17|^2.0", + "php": "^5.6|^7.0|^8.0", + "phpseclib/phpseclib": "~2.0||^3.0.2" + }, + "require-dev": { + "cache/filesystem-adapter": "^0.3.2|^1.1", + "composer/composer": "^1.10", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "phpcompatibility/php-compatibility": "^9.2", + "phpunit/phpunit": "^5.7||^8.5.13", + "squizlabs/php_codesniffer": "~2.3", + "symfony/css-selector": "~2.1", + "symfony/dom-crawler": "~2.1" + }, + "suggest": { + "cache/filesystem-adapter": "For caching certs and tokens (using Google\\Client::setCache)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Google\\": "src/" + }, + "files": [ + "src/aliases.php" + ], + "classmap": [ + "src/aliases.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "time": "2020-12-28T18:40:46+00:00" + }, + { + "name": "google/apiclient-services", + "version": "v0.156", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-api-php-client-services.git", + "reference": "2f5e54fdef034f856208328126bddd8376dae4b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/2f5e54fdef034f856208328126bddd8376dae4b3", + "reference": "2f5e54fdef034f856208328126bddd8376dae4b3", + "shasum": "" + }, + "require": { + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5" + }, + "type": "library", + "autoload": { + "psr-0": { + "Google_Service_": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "time": "2020-11-30T20:03:55+00:00" + }, + { + "name": "google/auth", + "version": "v1.14.3", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-auth-library-php.git", + "reference": "c1503299c779af0cbc99b43788f75930988852cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/c1503299c779af0cbc99b43788f75930988852cf", + "reference": "c1503299c779af0cbc99b43788f75930988852cf", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "~2.0|~3.0|~4.0|~5.0", + "guzzlehttp/guzzle": "^5.3.1|^6.2.1|^7.0", + "guzzlehttp/psr7": "^1.2", + "php": ">=5.4", + "psr/cache": "^1.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "guzzlehttp/promises": "0.1.1|^1.3", + "kelvinmo/simplejwt": "^0.2.5", + "phpseclib/phpseclib": "^2", + "phpunit/phpunit": "^4.8.36|^5.7", + "sebastian/comparator": ">=1.2.3", + "squizlabs/php_codesniffer": "^3.5" + }, + "suggest": { + "phpseclib/phpseclib": "May be used in place of OpenSSL for signing strings or for token management. Please require version ^2." + }, + "type": "library", + "autoload": { + "psr-4": { + "Google\\Auth\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google Auth Library for PHP", + "homepage": "http://github.com/google/google-auth-library-php", + "keywords": [ + "Authentication", + "google", + "oauth2" + ], + "time": "2020-10-16T21:33:48+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "1.0.x-dev", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "74acfe25f0019fb8af8b5b1eda0681e8e253fee2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/74acfe25f0019fb8af8b5b1eda0681e8e253fee2", + "reference": "74acfe25f0019fb8af8b5b1eda0681e8e253fee2", + "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" + }, + "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" + ], + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2020-11-28T23:32:07+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "0aa74dfb41ae110835923ef10a9d803a22d50e79" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/0aa74dfb41ae110835923ef10a9d803a22d50e79", + "reference": "0aa74dfb41ae110835923ef10a9d803a22d50e79", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.4", + "guzzlehttp/psr7": "^1.7", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "ext-curl": "*", + "php-http/client-integration-tests": "^3.0", + "phpunit/phpunit": "^8.5.5 || ^9.3.5", + "psr/log": "^1.1" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.1-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://github.com/alexeyshockov", + "type": "github" + }, + { + "url": "https://github.com/gmponos", + "type": "github" + } + ], + "time": "2020-10-10T11:47:56+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "ddfeedfff2a52661429437da0702979f708e6ac6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/ddfeedfff2a52661429437da0702979f708e6ac6", + "reference": "ddfeedfff2a52661429437da0702979f708e6ac6", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2020-10-19T16:50:15+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.x-dev", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "f47ece9e6e8ce74e3be04bef47f46061dc18c095" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f47ece9e6e8ce74e3be04bef47f46061dc18c095", + "reference": "f47ece9e6e8ce74e3be04bef47f46061dc18c095", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2020-12-08T11:45:39+00:00" + }, + { + "name": "jean85/pretty-package-versions", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "a917488320c20057da87f67d0d40543dd9427f7a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/a917488320c20057da87f67d0d40543dd9427f7a", + "reference": "a917488320c20057da87f67d0d40543dd9427f7a", + "shasum": "" + }, + "require": { + "composer/package-versions-deprecated": "^1.8.0", + "php": "^7.0|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0|^8.5|^9.2" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A wrapper for ocramius/package-versions to get pretty versions strings", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/1.5.1" + }, + "time": "2020-09-14T08:43:34+00:00" + }, + { + "name": "mongodb/mongodb", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/mongodb/mongo-php-library.git", + "reference": "b6d178f6738c5e0c8c3b49413d203c9d58f68460" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/b6d178f6738c5e0c8c3b49413d203c9d58f68460", + "reference": "b6d178f6738c5e0c8c3b49413d203c9d58f68460", + "shasum": "" + }, + "require": { + "ext-hash": "*", + "ext-json": "*", + "ext-mongodb": "^1.8.1", + "jean85/pretty-package-versions": "^1.2", + "php": "^7.0 || ^8.0", + "symfony/polyfill-php80": "^1.19" + }, + "require-dev": { + "squizlabs/php_codesniffer": "^3.5, <3.5.5", + "symfony/phpunit-bridge": "5.x-dev" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9.x-dev" + } + }, + "autoload": { + "psr-4": { + "MongoDB\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Andreas Braun", + "email": "andreas.braun@mongodb.com" + }, + { + "name": "Jeremy Mikola", + "email": "jmikola@gmail.com" + } + ], + "description": "MongoDB driver library", + "homepage": "https://jira.mongodb.org/browse/PHPLIB", + "keywords": [ + "database", + "driver", + "mongodb", + "persistence" + ], + "support": { + "issues": "https://github.com/mongodb/mongo-php-library/issues", + "source": "https://github.com/mongodb/mongo-php-library/tree/master" + }, + "time": "2021-01-13T09:40:57+00:00" + }, + { + "name": "monolog/monolog", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "78bd7bd33313c3a7ad1f2b0fc0c11a203d4e3826" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/78bd7bd33313c3a7ad1f2b0fc0c11a203d4e3826", + "reference": "78bd7bd33313c3a7ad1f2b0fc0c11a203d4e3826", + "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": "2020-12-15T22:21:44+00:00" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "shasum": "" + }, + "require": { + "php": "^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "time": "2020-12-06T15:14:20+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v2.0.19", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "446fc9faa5c2a9ddf65eb7121c0af7e857295241" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/446fc9faa5c2a9ddf65eb7121c0af7e857295241", + "reference": "446fc9faa5c2a9ddf65eb7121c0af7e857295241", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "time": "2020-10-15T10:06:57+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" + }, + "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" + ], + "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": "phpseclib/phpseclib", + "version": "3.0.x-dev", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "05d934c89f3597d6c3b0a88892ea4f0d76c3ac6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/05d934c89f3597d6c3b0a88892ea4f0d76c3ac6a", + "reference": "05d934c89f3597d6c3b0a88892ea4f0d76c3ac6a", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1|^2", + "paragonie/random_compat": "^1.4|^2.0", + "php": ">=5.6.1" + }, + "require-dev": { + "phing/phing": "~2.7", + "phpunit/phpunit": "^5.7|^6.0|^9.4", + "squizlabs/php_codesniffer": "~2.0" + }, + "suggest": { + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib3\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2021-01-08T15:01:31+00:00" + }, + { + "name": "psr/cache", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "b7f3937cd92526ccc1cc8bd1af67cb0a9ee1c766" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/b7f3937cd92526ccc1cc8bd1af67cb0a9ee1c766", + "reference": "b7f3937cd92526ccc1cc8bd1af67cb0a9ee1c766", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "time": "2020-12-14T17:31:09+00:00" + }, + { + "name": "psr/http-client", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "22b2ef5687f43679481615605d7a15c557ce85b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/22b2ef5687f43679481615605d7a15c557ce85b1", + "reference": "22b2ef5687f43679481615605d7a15c557ce85b1", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.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" + ], + "time": "2020-09-19T09:12:31+00:00" + }, + { + "name": "psr/http-message", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "efd67d1dc14a7ef4fc4e518e7dee91c271d524e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/efd67d1dc14a7ef4fc4e518e7dee91c271d524e4", + "reference": "efd67d1dc14a7ef4fc4e518e7dee91c271d524e4", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2019-08-29T13:16:46+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" + }, + "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" + ], + "time": "2020-09-18T06:44:51+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "react/promise", + "version": "2.x-dev", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "a8ec7b446d6673901e3be20258d12b6b980af92f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/a8ec7b446d6673901e3be20258d12b6b980af92f", + "reference": "a8ec7b446d6673901e3be20258d12b6b980af92f", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + }, + { + "url": "https://github.com/cboden", + "type": "github" + }, + { + "url": "https://github.com/clue", + "type": "github" + }, + { + "url": "https://github.com/jsor", + "type": "github" + } + ], + "time": "2020-07-23T20:41:09+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" + }, + "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" + ], + "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": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", + "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "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" + ], + "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-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" + }, + "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" + ], + "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": "a9d2cd2fa893e90dc6ab6545255712a46d0a57fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a9d2cd2fa893e90dc6ab6545255712a46d0a57fc", + "reference": "a9d2cd2fa893e90dc6ab6545255712a46d0a57fc", + "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.8 || ^9.4" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.2-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" + ], + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2020-12-03T22:44:43+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": { + "vlucas/phpdotenv": 20, + "guzzlehttp/guzzle": 20, + "elasticsearch/elasticsearch": 20, + "mongodb/mongodb": 20, + "monolog/monolog": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "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..c011f8984 --- /dev/null +++ b/app/public/index.php @@ -0,0 +1,11 @@ +run(); +} catch (\Exception $e) { + echo $e->getMessage(); +} diff --git a/app/src/hw/App.php b/app/src/hw/App.php new file mode 100644 index 000000000..ad6999c37 --- /dev/null +++ b/app/src/hw/App.php @@ -0,0 +1,36 @@ +getService()); + $platform->run(); + } + + /** + * @throws Exception + */ + private function getService(): VideoSharingServiceInterface + { + switch ($_ENV['VIDEOPLATFORM']) { + case YoutubeService::PLATFORM_NAME: + return new YoutubeService(); + default: + throw new AppException('undefined video platform'); + } + } +} diff --git a/app/src/hw/DB/ElasticSearch.php b/app/src/hw/DB/ElasticSearch.php new file mode 100644 index 000000000..0266392c0 --- /dev/null +++ b/app/src/hw/DB/ElasticSearch.php @@ -0,0 +1,124 @@ +client = ClientBuilder::create() + ->setHosts([$_ENV['ELASTIC_SEARCH_HOST']]) + ->build(); + } + + /** + * @param array $data + * @return mixed + * @throws Exception + */ + public function save(array $data) + { + $correctData = ArrayHelper::getCorrectFormat($this, $data); + + $result = $this->client->index($correctData); + + if ($result) { + return $result['_id']; + } + + return false; + } + + /** + * @param $index + * @param $id + * @return array + * @throws Exception + */ + public function findById($index, $id): array + { + $params = [ + 'index' => $index, + 'id' => $id, + 'client' => [ 'ignore' => 404 ] + ]; + + $result = $this->client->get($params); + + if (false === $result['found']) { + throw new Exception('Not found'); + } + + return $result['_source']; + } + + /** + * @param $index + * @param $queryParams + * example: + * [ + * 'where' => ['channelId' => 'someId']', + * 'limit' => 100, + * 'offset' => 0 + * ] + * @return array|callable + * @throws Exception + */ + public function query($index, $queryParams = []) + { + $params = [ + 'index' => $index, + 'body' => [ + 'query' => [ + 'match' => $queryParams['where'] + ] + ], + 'size' => $queryParams['limit'], + 'from' => $queryParams['offset'], + 'client' => [ 'ignore' => 404 ] + ]; + + $result = $this->client->search($params); + + if (empty($response['hits']['hits'])) { + AppLogger::addLog(Logger::WARNING,'not found by query', $params); + } + + return $result; + } + + /** + * получает все записи, по лимиту и офсету + * @param $index + * @param $limit + * @param $offset + * @return array|callable + */ + public function getAll($index, $limit, $offset) + { + $params = [ + 'index' => $index, + 'size' => $limit, + 'from' => $offset, + 'client' => [ 'ignore' => 404 ] + ]; + + $result = $this->client->search($params); + + if (empty($response['hits']['hits'])) { + AppLogger::addLog(Logger::WARNING, 'not found by index: ' . $index, $params); + } + + return $result; + } +} \ No newline at end of file diff --git a/app/src/hw/DB/MongoDB.php b/app/src/hw/DB/MongoDB.php new file mode 100644 index 000000000..67b2353f6 --- /dev/null +++ b/app/src/hw/DB/MongoDB.php @@ -0,0 +1,55 @@ + $_ENV['MONGODB_USERNAME'], 'password' => $_ENV['MONGODB_PASSWORD']]; + $this->client = new Client('mongodb://' . $_ENV['MONGODB_HOST'] . ':' . $_ENV['MONGODB_PORT'], $options); + $this->client->selectDatabase($_ENV['MONGODB_DATABASE']); + } + + public function save(array $data): bool + { + $collection = $this->client->otus->{$data['tableName']}; + + $result = $collection->insertOne($data); + + if ($result) { + return true; + } + + return false; + } + + public function findById($tableName, $id): array + { + return []; + } + + public function query($tableName, $queryParams) + { + return []; + } + + public function getAll($tableName, $limit, $offset) + { + return []; + } +} diff --git a/app/src/hw/VideoPlatform.php b/app/src/hw/VideoPlatform.php new file mode 100644 index 000000000..9120f513a --- /dev/null +++ b/app/src/hw/VideoPlatform.php @@ -0,0 +1,107 @@ +service = $service; + } + + /** + * анализ канала + * - данные о канале + * - данные о видео этого канала + * сохраняет в noSql хранилище + * + * @return mixed + * @throws Exception + */ + public function analyze() + { + $this->validateParam(); + return $this->service->analyze(); + } + + /** + * Вернет статистику канала. А именно: + * [ + * 'totalLikes' => 123, + * 'totalDislikes' => 12, + * ] + * @return mixed + * @throws Exception + */ + public function getStatistics() + { + $this->validateParam(); + return $this->service->getStatistics(); + } + + /** + * Топ N каналов по соотношению totalLikes/Dislikes + * N - передается как параметр и находится в $_SERVER[argv] + * + * @return mixed + */ + public function getTopChannels() + { + return $this->service->getTopChannels(); + } + + /** + * @throws Exception + */ + public function run() + { + switch ($_SERVER['argv'][1]) { + case self::ANALYZE: + $result = $this->analyze(); + break; + case self::STATISTICS: + $result = $this->getStatistics(); + break; + case self::TOP_N: + $result = $this->getTopChannels(); + break; + default: + throw new Exception( + 'Необходимо передать тип: php index.php [' . self::ANALYZE . '|' . self::STATISTICS . '|' . self::TOP_N . ']' + ); + } + + print_r($result); + } + + /** + * @param $id + * @return + */ + public function findChannelById($id) + { + return $this->service->findChannelById($id); + } + + /** + * @throws Exception + */ + private function validateParam() + { + if (empty($_SERVER['argv'][2])) { + throw new AppException("необходимо передать id каналов через запятую. Пример: php index.php analyze|statistics id1,id2,id3 \n"); + } + + return true; + } +} diff --git a/app/src/hw/exceptions/AppException.php b/app/src/hw/exceptions/AppException.php new file mode 100644 index 000000000..20421fa71 --- /dev/null +++ b/app/src/hw/exceptions/AppException.php @@ -0,0 +1,16 @@ + $data['tableName'], + 'id' => $data['id'], + 'body' => $data + ]; + } + + /** + * @param $data + * @param $index + * @return array|bool + */ + public static function index($data, $index) + { + foreach ($data as $key => $value) { + if ($key === $index) { + return [ + $value => $data + ]; + } + } + + return false; + } + + public static function getColumn(array $array, string $column): array + { + $result = []; + + foreach ($array as $item) { + foreach ($item as $key => $value) { + if ($key == $column) { + $result[] = $value; + } + } + } + + return $result; + } +} diff --git a/app/src/hw/interfaces/DBInterface.php b/app/src/hw/interfaces/DBInterface.php new file mode 100644 index 000000000..5e7e88628 --- /dev/null +++ b/app/src/hw/interfaces/DBInterface.php @@ -0,0 +1,17 @@ +pushHandler(new StreamHandler('../logs/app.log')); + $log->addRecord($level, $message, $context); + } +} \ No newline at end of file diff --git a/app/src/hw/models/ActiveRecord.php b/app/src/hw/models/ActiveRecord.php new file mode 100644 index 000000000..7738cc8e2 --- /dev/null +++ b/app/src/hw/models/ActiveRecord.php @@ -0,0 +1,12 @@ +objects[$key])){ + return $inst->objects[$key]; + } + return null; + } + + /** + * Adding object to ObjectWatcher registry. + * @param $obj + * @param int $id + */ + public static function addRecord($obj, $id) { + $inst = self::getInstance(); + $inst->objects[$inst->getKey($obj, $id)] = $obj; + } + + function getKey($obj, $id){ + return get_class($obj).'.'.$id; + } +} diff --git a/app/src/hw/models/youtube/Channel.php b/app/src/hw/models/youtube/Channel.php new file mode 100644 index 000000000..ce416c5b4 --- /dev/null +++ b/app/src/hw/models/youtube/Channel.php @@ -0,0 +1,190 @@ +tableName; + } + + /** + * @param mixed $id + */ + public function setId($id): void + { + $this->id = $id; + } + + /** + * @param mixed $title + */ + public function setTitle($title): void + { + $this->title = $title; + } + + /** + * @param mixed $description + */ + public function setDescription($description): void + { + $this->description = $description; + } + + /** + * @param mixed $viewCount + */ + public function setViewCount($viewCount): void + { + $this->viewCount = $viewCount; + } + + /** + * @param mixed $subscriberCount + */ + public function setSubscriberCount($subscriberCount): void + { + $this->subscriberCount = $subscriberCount; + } + + /** + * @param mixed $videoCount + */ + public function setVideoCount($videoCount): void + { + $this->videoCount = $videoCount; + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getDescription() + { + return $this->description; + } + + /** + * @return mixed + */ + public function getSubscriberCount() + { + return $this->subscriberCount; + } + + /** + * @return mixed + */ + public function getTitle() + { + return $this->title; + } + + /** + * @return mixed + */ + public function getVideoCount() + { + return $this->videoCount; + } + + /** + * @return mixed + */ + public function getViewCount() + { + return $this->viewCount; + } + + /** + * @param DBInterface $db + * @param $id + * @return Channel + */ + public static function findById(DBInterface $db, $id): self + { + $result = $db->findById((new self())->tableName, $id); + + $identityMap = ObjectWatcher::getRecord(self::class, $id); + + if ($identityMap) { + return $identityMap; + } + + $channel = new self(); + $channel->setId($result['id']); + $channel->setDescription($result['description']); + $channel->setSubscriberCount($result['subscriberCount']); + $channel->setTitle($result['title']); + $channel->setVideoCount($result['videoCount']); + $channel->setViewCount($result['viewCount']); + + ObjectWatcher::addRecord($channel, $channel->getId()); + + return $channel; + } + + public static function getAll(DBInterface $db, $limit = 100, $offset = 0) + { + $response = $db->getAll((new self())->getTableName(), $limit, $offset); + + $result = []; + + while (!empty($response['hits']['hits'])) { + + foreach ($response['hits']['hits'] as $hit){ + $result[] = $hit; + } + + $offset = $limit + $offset; + $response = $db->getAll((new self())->getTableName(), $limit, $offset); + } + + return $result; + } + + /** + * @param DBInterface $db + */ + public function save(DBInterface $db) + { + return $db->save($this->getProperties()); + } + + /** + * @return array + */ + public function getProperties() + { + return get_object_vars($this); + } +} diff --git a/app/src/hw/models/youtube/Video.php b/app/src/hw/models/youtube/Video.php new file mode 100644 index 000000000..9f7417530 --- /dev/null +++ b/app/src/hw/models/youtube/Video.php @@ -0,0 +1,230 @@ +tableName; + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id): void + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getPublishedAt() + { + return $this->publishedAt; + } + + /** + * @param mixed $publishedAt + */ + public function setPublishedAt($publishedAt): void + { + $this->publishedAt = $publishedAt; + } + + /** + * @return mixed + */ + public function getChannelId() + { + return $this->channelId; + } + + /** + * @param mixed $channelId + */ + public function setChannelId($channelId): void + { + $this->channelId = $channelId; + } + + /** + * @return mixed + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param mixed $title + */ + public function setTitle($title): void + { + $this->title = $title; + } + + /** + * @return mixed + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param mixed $description + */ + public function setDescription($description): void + { + $this->description = $description; + } + + /** + * @return mixed + */ + public function getCategoryId() + { + return $this->categoryId; + } + + /** + * @param mixed $categoryId + */ + public function setCategoryId($categoryId): void + { + $this->categoryId = $categoryId; + } + + /** + * @return mixed + */ + public function getViewCount() + { + return $this->viewCount; + } + + /** + * @param mixed $viewCount + */ + public function setViewCount($viewCount): void + { + $this->viewCount = $viewCount; + } + + /** + * @return mixed + */ + public function getLikeCount() + { + return $this->likeCount; + } + + /** + * @param mixed $likeCount + */ + public function setLikeCount($likeCount): void + { + $this->likeCount = $likeCount; + } + + /** + * @return mixed + */ + public function getDislikeCount() + { + return $this->dislikeCount; + } + + /** + * @param mixed $dislikeCount + */ + public function setDislikeCount($dislikeCount): void + { + $this->dislikeCount = $dislikeCount; + } + + /** + * @return mixed + */ + public function getCommentCount() + { + return $this->commentCount; + } + + /** + * @param mixed $commentCount + */ + public function setCommentCount($commentCount): void + { + $this->commentCount = $commentCount; + } + + /** + * @param DBInterface $db + */ + public function save(DBInterface $db) + { + return $db->save($this->getProperties()); + } + + /** + * @return array + */ + public function getProperties() + { + return get_object_vars($this); + } + + public static function findById(DBInterface $db, $id): self + { + $result = $db->findById((new self())->tableName, $id); + + $video = new self(); + $video->setId($result['id']); + $video->setPublishedAt($result['publishedAt']); + $video->setChannelId($result['channelId']); + $video->setTitle($result['title']); + $video->setDescription($result['description']); + $video->setCategoryId($result['categoryId']); + $video->setViewCount($result['viewCount']); + $video->setLikeCount($result['likeCount']); + $video->setDislikeCount($result['dislikeCount']); + $video->setCommentCount($result['commentCount']); + + return $video; + } + + public static function getAll(DBInterface $db, $limit, $offset) + { + // TODO: Implement getAll() method. + } +} \ No newline at end of file diff --git a/app/src/hw/services/YoutubeService.php b/app/src/hw/services/YoutubeService.php new file mode 100644 index 000000000..88cf89932 --- /dev/null +++ b/app/src/hw/services/YoutubeService.php @@ -0,0 +1,254 @@ +getConfig(); + + $this->apiKey = $config['api_key']; + $this->clientSecret = $config['client_secret']; + + $this->identifyDb(); + } + + /** + * @return array + */ + public function getConfig(): array + { + return [ + 'api_key' => $_ENV['YOUTUBE_API_KEY'], + 'client_secret' => $_ENV['YOUTUBE_CLIENT_SECRET'] + ]; + } + + /** + * @return array + * @throws GuzzleException|AppException + */ + public function getChannelDetail(): array + { + + $url = $this->baseUrl . '/channels?part=snippet,contentDetails,statistics' . '&id=' . trim($_SERVER['argv'][2]) + . '&key=' . $this->apiKey; + + $data = $this->sendRequest('GET', $url); + + if (empty($data['items'])) { + throw new AppException('not found'); + } + + return $data['items']; + } + + /** + * @param $channelId + * @param string $nextPageToken + * @return array + * @throws GuzzleException + */ + public function getVideos($channelId, $nextPageToken = ''): array + { + $url = $this->baseUrl . '/search?channelId=' . $channelId . '&part=snippet&order=date&maxResults=50' . + '&key=' . $this->apiKey; + + if (!empty($nextPageToken)) $url .= '&pageToken=' . $nextPageToken; + + return $this->sendRequest('GET', $url); + } + + /** + * @param $videoIds + * @return array + * @throws GuzzleException|AppException + */ + public function getVideoDetail($videoIds): array + { + $videoIds = implode(',' , $videoIds); + + $url = $this->baseUrl . '/videos?part=snippet,statistics&id=' . $videoIds . '&key=' . $this->apiKey; + + $data = $this->sendRequest('GET', $url); + + if (empty($data['items'])) { + throw new AppException('not found'); + } + + return $data['items']; + } + + /** + * Получит данные о канале и видео канала, затем сохраняет в хранилище + * @throws GuzzleException + * @throws AppException + */ + public function analyze() + { + $channelDetails = $this->getChannelDetail(); + + foreach ($channelDetails as $channel) { + $this->saveChannelDetails($channel); + + $videos = $this->getVideos($channel['id']); + $ids = $this->getVideoIds($videos); + + if (empty($ids)) { + AppLogger::addLog(Logger::NOTICE, "There is no any video on channel: " . $channel['id']); + continue; + } + + $videosDetails = $this->getVideoDetail($ids); + $this->saveChannelVideos($videosDetails); + + while (!empty($videos['nextPageToken'])) { + $videos = $this->getVideos($channel['id'], $videos['nextPageToken']); + $ids = $this->getVideoIds($videos); + + if (empty($ids)) { + AppLogger::addLog(Logger::NOTICE, "There is no any video on channel: " . $channel['id']); + continue 2; + } + + $videosDetails = $this->getVideoDetail($ids); + $this->saveChannelVideos($videosDetails); + } + } + } + + /** + * @param $details + */ + public function saveChannelDetails($details) + { + $channel = new Channel(); + $channel->setId($details['id']); + $channel->setTitle($details['snippet']['title']); + $channel->setDescription($details['snippet']['description']); + $channel->setViewCount($details['statistics']['viewCount']); + $channel->setSubscriberCount($details['statistics']['subscriberCount']); + $channel->setVideoCount($details['statistics']['videoCount']); + + $result = $channel->save($this->db); + echo "Channel ID: $result \n"; + } + + public function saveChannelVideos($videoDetails) + { + foreach ($videoDetails as $videoDetail) { + $video = new Video(); + + $video->setId($videoDetail['id']); + $video->setPublishedAt($videoDetail['snippet']['publishedAt']); + $video->setChannelId($videoDetail['snippet']['channelId']); + $video->setTitle($videoDetail['snippet']['title']); + $video->setDescription($videoDetail['snippet']['description']); + $video->setCategoryId($videoDetail['snippet']['categoryId']); + $video->setViewCount($videoDetail['viewCount']); + $video->setLikeCount($videoDetail['statistics']['likeCount']); + $video->setDislikeCount($videoDetail['statistics']['dislikeCount']); + $video->setCommentCount($videoDetail['statistics']['commentCount']); + + $result = $video->save($this->db); + echo "Video ID: $result \n"; + } + } + + /** + * @param $id + * @return Channel + */ + public function findChannelById($id) + { + return Channel::findById($this->db, $id); + } + + /** + * @throws \Exception + */ + private function identifyDb(): void + { + switch ($_ENV['NO_SQL_DB']) { + case DBInterface::ELASTIC_SEARCH; + $this->db = new ElasticSearch(); + break; + case DBInterface::MONGO_DB: + $this->db = new MongoDB(); + break; + default: + throw new \Exception('wrong db'); + } + } + + /** + * @param $videos + * @return array + */ + private function getVideoIds($videos) + { + $ids = ArrayHelper::getColumn($videos['items'], 'id'); + return ArrayHelper::getColumn($ids, 'videoId'); + } + + /** + * тут собирается статистика по лайкам/дислайкам + * + * @return array + */ + public function getStatistics() + { + $channelId = $_SERVER['argv'][2]; + + $channel = Channel::findById($this->db, $channelId); + $youtubeStatistics = new YoutubeChannelStatistics($this->db); + $statistics = $youtubeStatistics->getTotalLikesDislikes($channel->getId()); + + return [ + 'channelId'=> $channelId, + 'LikeDislikeCounter' => $statistics + ]; + } + + /** + * вернет топ N каналов по соотношению totalLikes/totalDislikes + * + * @throws \Exception + */ + public function getTopChannels() + { + $n = (int)$_SERVER['argv'][2]; + + if (false === is_int($n) or $n < 1) { + throw new AppException('specify an integer'); + } + + $topN = new YoutubeChannelStatistics($this->db); + return $topN->getTopChannels($n); + } +} diff --git a/app/src/hw/statistics/YoutubeChannelStatistics.php b/app/src/hw/statistics/YoutubeChannelStatistics.php new file mode 100644 index 000000000..980184af6 --- /dev/null +++ b/app/src/hw/statistics/YoutubeChannelStatistics.php @@ -0,0 +1,78 @@ +db = $db; + } + + public function getTotalLikesDislikes($channelId) + { + $queryParams = [ + 'where' => [ + 'channelId' => $channelId + ], + 'limit' => 200, + 'offset' => 0 + ]; + + $response = $this->db->query((new Video())->getTableName(), $queryParams); + + $totalLikes = 0; + $totalDislikes = 0; + + /* + * $response['hits']['total']['value'] вот эта штука возвращает всегда total в индексе, а не в hits + * поэтому не получится определить через $response['hits']['total']['value'] > 0 + * здесь наверное тогда лучше через !empty($response['hits']['hits']) или isset($response['hits']['hits'][0]) + * хотя даже если использовать count($response['hits']['hits']), я же поставил лимит, разом максимум 200 записей + */ + while (!empty($response['hits']['hits'])) { + + foreach ($response['hits']['hits'] as $hit) { + $totalLikes = $totalLikes + $hit['_source']['likeCount']; + $totalDislikes = $totalDislikes + $hit['_source']['dislikeCount']; + } + + $queryParams['offset'] = $queryParams['limit'] + $queryParams['offset']; + $response = $this->db->query((new Video())->getTableName(), $queryParams); + } + + return ['totalLikes' => $totalLikes, 'totalDislikes' => $totalDislikes]; + } + + /** + * вернет топ N каналов по соотношению totalLikes/totalDislikes + * @param int $topN + * @return array + */ + public function getTopChannels(int $topN) + { + $channels = Channel::getAll($this->db); + + $result = []; + + foreach ($channels as $channel) { + $total= $this->getTotalLikesDislikes($channel['_id']); + $value = $total['totalLikes']/$total['totalDislikes']; + $result[] = [ + "channel_id" => $channel['_id'], + "value" => $value + ]; + } + + usort($result, function($a, $b) { + return $b['value'] <=> $a['value']; + }); + + return array_slice($result, 0, $topN); + } +} \ No newline at end of file diff --git a/app/src/hw/traits/RequestTrait.php b/app/src/hw/traits/RequestTrait.php new file mode 100644 index 000000000..fdbb5dda7 --- /dev/null +++ b/app/src/hw/traits/RequestTrait.php @@ -0,0 +1,28 @@ +request($method, $url, $data); + return !empty($result) ? json_decode($result->getBody(), true) : []; + }catch (\Exception $e){ + http_response_code($e->getCode()); + throw $e; + } + } +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..88b309df0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,41 @@ +version: '3.8' + +services: + nginx: + container_name: nginx + build: + context: ./docker/nginx + volumes: + - ./app:/var/www/hw-otus + - ./docker/nginx/config/default.conf:/etc/nginx/conf.d/default.conf + ports: + - "8787:80" + + php-fpm: + container_name: php-fpm + build: + context: ./docker/php-fpm + volumes: + - ./app:/var/www/hw-otus + + elastic-search: + container_name: elastic-search + build: + context: ./docker/elastic-search + ports: + - 9200:9200 + environment: + - discovery.type=single-node + + mongo-db: + container_name: mongo-db + build: + context: ./docker/mongo-db + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: root + MONGO_INITDB_DATABASE: otus + volumes: + - ./docker/mongo-db/init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro + ports: + - 27017:27017 \ No newline at end of file diff --git a/docker/elastic-search/Dockerfile b/docker/elastic-search/Dockerfile new file mode 100644 index 000000000..d582d1f5b --- /dev/null +++ b/docker/elastic-search/Dockerfile @@ -0,0 +1 @@ +FROM elasticsearch:7.9.3 \ No newline at end of file diff --git a/docker/mongo-db/Dockerfile b/docker/mongo-db/Dockerfile new file mode 100644 index 000000000..cbe76502d --- /dev/null +++ b/docker/mongo-db/Dockerfile @@ -0,0 +1 @@ +FROM mongo:3.6.21 diff --git a/docker/mongo-db/init-mongo.js b/docker/mongo-db/init-mongo.js new file mode 100644 index 000000000..236071745 --- /dev/null +++ b/docker/mongo-db/init-mongo.js @@ -0,0 +1,10 @@ +db.createUser( + { + user:"root", + pwd:"root", + roles: { + role:"readWrite", + db:"otus" + } + } +) \ No newline at end of file diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile new file mode 100644 index 000000000..45ad9f589 --- /dev/null +++ b/docker/nginx/Dockerfile @@ -0,0 +1,3 @@ +FROM nginx + +WORKDIR /var/www/hw-otus \ No newline at end of file diff --git a/docker/nginx/config/default.conf b/docker/nginx/config/default.conf new file mode 100644 index 000000000..e6ba61102 --- /dev/null +++ b/docker/nginx/config/default.conf @@ -0,0 +1,21 @@ +server { + + root /var/www/hw-otus/public; + index index.php; + + listen 80; + + location / { + try_files $uri $uri/ /index.php$is_args$args; + } + + # Server PHP config + location ~ \.php { + fastcgi_pass php-fpm:9000; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + try_files $uri =404; + fastcgi_index index.php; + } +} \ No newline at end of file diff --git a/docker/php-fpm/Dockerfile b/docker/php-fpm/Dockerfile new file mode 100644 index 000000000..2a8ca35d3 --- /dev/null +++ b/docker/php-fpm/Dockerfile @@ -0,0 +1,26 @@ +FROM php:7.4-fpm + +#необходимые утилиты +RUN apt-get update && apt-get install -y \ +curl \ +libssl-dev \ +libzip-dev \ +zip \ +git \ +wget \ +grep \ +libz-dev \ +libmemcached-dev \ +libpq-dev \ +libcurl4-openssl-dev \ +nano \ +&& docker-php-ext-install zip + +RUN pecl install mongodb \ + && echo "extension=mongodb.so" > /usr/local/etc/php/conf.d/mongo.ini + +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer + +WORKDIR /var/www/hw-otus/ +EXPOSE 9000 +CMD ["php-fpm"] \ No newline at end of file