Reunify AzuraCore and AzuraCast repositories.

This commit is contained in:
Buster "Silver Eagle" Neece 2020-02-05 20:35:13 -06:00
parent 14da17c242
commit 4d4d75ad4d
No known key found for this signature in database
GPG Key ID: 6D9E12FF03411F4E
268 changed files with 5589 additions and 523 deletions

View File

@ -6,13 +6,13 @@ ini_set('display_errors', 1);
$autoloader = require dirname(__DIR__) . '/vendor/autoload.php';
$app = App\AppFactory::create($autoloader, [
Azura\Settings::BASE_DIR => dirname(__DIR__),
App\Settings::BASE_DIR => dirname(__DIR__),
]);
$di = $app->getContainer();
App\Customization::initCli();
/** @var Azura\Console\Application $cli */
$cli = $di->get(Azura\Console\Application::class);
/** @var App\Console\Application $cli */
$cli = $di->get(App\Console\Application::class);
$cli->run();

View File

@ -17,43 +17,66 @@
"ext-xml": "*",
"ext-xmlwriter": "*",
"azuracast/azuracore": "dev-master",
"azuracast/azuraforms": "dev-master",
"azuracast/nowplaying": "dev-master",
"bacon/bacon-qr-code": "^2.0",
"bernard/bernard": "dev-master",
"brick/math": "^0.8.4",
"cache/array-adapter": "^1.0",
"cache/prefixed-cache": "^1.0",
"cache/psr-6-doctrine-bridge": "^3.0",
"cache/redis-adapter": "^1.0",
"cakephp/chronos": "^1.1",
"composer/ca-bundle": "^1.2",
"doctrine/annotations": "^1.6",
"doctrine/data-fixtures": "^1.3",
"doctrine/dbal": "^2.8",
"doctrine/migrations": "^2",
"doctrine/orm": "~2.6",
"gettext/gettext": "^4.4",
"guzzlehttp/guzzle": ">6.0",
"guzzlehttp/oauth-subscriber": "^0.3.0",
"http-interop/http-factory-guzzle": "^1.0",
"influxdb/influxdb-php": "^1.14.3",
"james-heinrich/getid3": "dev-master",
"jhofm/flysystem-iterator": "^2.1",
"laminas/laminas-config": "^3.3",
"league/flysystem": "^1.0",
"league/flysystem-aws-s3-v3": "^1.0",
"league/flysystem-cached-adapter": "^1.0",
"league/plates": "^3.1",
"lstrojny/fxmlrpc": "^0.14.0",
"maxmind-db/reader": "~1.0",
"mezzio/mezzio-session": "^1.3",
"mezzio/mezzio-session-cache": "^1.3",
"mnapoli/silly-php-di": "^1.2",
"mobiledetect/mobiledetectlib": "^2.8",
"monolog/monolog": "^2",
"myclabs/deep-copy": "^1.9",
"ocramius/doctrine-batch-utils": "^2.0",
"php-http/socket-client": "^1.2",
"php-http/message": "^1.4",
"php-di/php-di": "^6.0",
"php-di/slim-bridge": "^3.0",
"php-http/guzzle6-adapter": "^1.1",
"php-http/message": "^1.4",
"php-http/socket-client": "^1.2",
"ramsey/uuid": "^3.8",
"sentry/sentry": "^2",
"slim/http": "^0.8",
"slim/slim": "^4.2",
"spomky-labs/otphp": "^9.1",
"studio24/rotate": "^1.0",
"supervisorphp/supervisor": "^3.0",
"symfony/console": "^4.3",
"symfony/event-dispatcher": "^4.3",
"symfony/finder": "^4.3",
"symfony/process": "^4.3",
"symfony/property-access": "^4.3",
"ramsey/uuid": "^3.8",
"symfony/serializer": "^4.3",
"symfony/validator": "^4.3",
"voku/portable-utf8": "^5.4",
"wikimedia/composer-merge-plugin": "^1.4",
"zendframework/zend-config": "^3.3",
"zircote/swagger-php": "^3.0",
"jhofm/flysystem-iterator": "^2.1"
"zircote/swagger-php": "^3.0"
},
"require-dev": {
"codeception/codeception": "^4.0",

290
composer.lock generated
View File

@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "cc59b6eaf1ea72f6d51c53ada8161095",
"content-hash": "b78acc190be3074ca4665d4110be8bc2",
"packages": [
{
"name": "aws/aws-sdk-php",
"version": "3.133.6",
"version": "3.133.7",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "cd7bd2fdd159146ef6c7eeb90b73fae4fd11da57"
"reference": "cd6fb07aed2cc68088251e3c572d111d67d558a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/cd7bd2fdd159146ef6c7eeb90b73fae4fd11da57",
"reference": "cd7bd2fdd159146ef6c7eeb90b73fae4fd11da57",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/cd6fb07aed2cc68088251e3c572d111d67d558a3",
"reference": "cd6fb07aed2cc68088251e3c572d111d67d558a3",
"shasum": ""
},
"require": {
@ -88,81 +88,7 @@
"s3",
"sdk"
],
"time": "2020-01-24T19:11:35+00:00"
},
{
"name": "azuracast/azuracore",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/AzuraCast/azuracore.git",
"reference": "544b3526ac42e6d2852e8052193f0221611da97c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/AzuraCast/azuracore/zipball/544b3526ac42e6d2852e8052193f0221611da97c",
"reference": "544b3526ac42e6d2852e8052193f0221611da97c",
"shasum": ""
},
"require": {
"cache/array-adapter": "^1.0",
"cache/prefixed-cache": "^1.0",
"cache/psr-6-doctrine-bridge": "^3.0",
"cache/redis-adapter": "^1.0",
"composer/ca-bundle": "^1.2",
"doctrine/data-fixtures": "^1.3",
"doctrine/dbal": "^2.8",
"doctrine/migrations": "^2",
"doctrine/orm": "~2.6",
"ext-fileinfo": "*",
"ext-json": "*",
"ext-pdo": "*",
"ext-redis": "*",
"guzzlehttp/guzzle": ">6.0",
"http-interop/http-factory-guzzle": "^1.0",
"league/plates": "^3.1",
"mezzio/mezzio-session": "^1.3",
"mezzio/mezzio-session-cache": "^1.3",
"mnapoli/silly-php-di": "^1.2",
"monolog/monolog": "^2",
"php": ">=7.4",
"php-di/php-di": "^6.0",
"php-di/slim-bridge": "^3.0",
"slim/http": "^0.8",
"slim/slim": "^4.2",
"symfony/console": "^4.3",
"symfony/event-dispatcher": "^4.3",
"symfony/serializer": "^4.3",
"symfony/validator": "^4.3"
},
"require-dev": {
"codeception/codeception": "^4.0",
"codeception/module-asserts": "^1.1",
"codeception/module-phpbrowser": "^1.0",
"mockery/mockery": "^1.0",
"overtrue/phplint": "^1.1",
"phpstan/phpstan": "^0.11.1",
"phpstan/phpstan-strict-rules": "^0.11.0",
"roave/security-advisories": "dev-master"
},
"type": "library",
"autoload": {
"psr-4": {
"Azura\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Buster Neece",
"email": "buster@busterneece.com"
}
],
"description": "A lightweight core application framework.",
"time": "2020-01-18T01:31:14+00:00"
"time": "2020-02-04T19:11:15+00:00"
},
{
"name": "azuracast/azuraforms",
@ -170,12 +96,12 @@
"source": {
"type": "git",
"url": "https://github.com/AzuraCast/azuraforms.git",
"reference": "6cc5fb9139369cd16d5b09ed5fe9bd43a61720ff"
"reference": "3a64e491f99afedf0d2be342b8788867a4b167b7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/AzuraCast/azuraforms/zipball/6cc5fb9139369cd16d5b09ed5fe9bd43a61720ff",
"reference": "6cc5fb9139369cd16d5b09ed5fe9bd43a61720ff",
"url": "https://api.github.com/repos/AzuraCast/azuraforms/zipball/3a64e491f99afedf0d2be342b8788867a4b167b7",
"reference": "3a64e491f99afedf0d2be342b8788867a4b167b7",
"shasum": ""
},
"require": {
@ -213,7 +139,7 @@
],
"description": "A modern, namespaced, configuration-driven forms engine for PHP.",
"homepage": "https://github.com/AzuraCast/azuraforms",
"time": "2019-09-23T03:15:28+00:00"
"time": "2020-02-01T03:18:09+00:00"
},
{
"name": "azuracast/nowplaying",
@ -491,16 +417,16 @@
},
{
"name": "brick/math",
"version": "0.8.11",
"version": "0.8.12",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
"reference": "bf4894d6373d396666d280a42ecdf1ad75f8222f"
"reference": "ea9a095b902f5d42126aba4455a64476f5528241"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/bf4894d6373d396666d280a42ecdf1ad75f8222f",
"reference": "bf4894d6373d396666d280a42ecdf1ad75f8222f",
"url": "https://api.github.com/repos/brick/math/zipball/ea9a095b902f5d42126aba4455a64476f5528241",
"reference": "ea9a095b902f5d42126aba4455a64476f5528241",
"shasum": ""
},
"require": {
@ -508,7 +434,8 @@
},
"require-dev": {
"php-coveralls/php-coveralls": "2.*",
"phpunit/phpunit": "7.*"
"phpunit/phpunit": "7.*",
"vimeo/psalm": "3.*"
},
"type": "library",
"autoload": {
@ -531,7 +458,7 @@
"brick",
"math"
],
"time": "2020-01-23T00:19:01+00:00"
"time": "2020-01-27T13:00:05+00:00"
},
{
"name": "cache/adapter-common",
@ -1174,16 +1101,16 @@
},
{
"name": "dflydev/fig-cookies",
"version": "v2.0.0",
"version": "v2.0.1",
"source": {
"type": "git",
"url": "https://github.com/dflydev/dflydev-fig-cookies.git",
"reference": "a59857139b9e30978b5b802b3631b5eaf34e8c66"
"reference": "733af78ddad60aec96f7c4a1204619dd4d62afff"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dflydev/dflydev-fig-cookies/zipball/a59857139b9e30978b5b802b3631b5eaf34e8c66",
"reference": "a59857139b9e30978b5b802b3631b5eaf34e8c66",
"url": "https://api.github.com/repos/dflydev/dflydev-fig-cookies/zipball/733af78ddad60aec96f7c4a1204619dd4d62afff",
"reference": "733af78ddad60aec96f7c4a1204619dd4d62afff",
"shasum": ""
},
"require": {
@ -1224,7 +1151,7 @@
"psr-7",
"psr7"
],
"time": "2018-07-11T06:54:37+00:00"
"time": "2020-01-02T16:13:22+00:00"
},
{
"name": "doctrine/annotations",
@ -3247,16 +3174,16 @@
},
{
"name": "league/flysystem",
"version": "1.0.63",
"version": "1.0.64",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "8132daec326565036bc8e8d1876f77ec183a7bd6"
"reference": "d13c43dbd4b791f815215959105a008515d1a2e0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/8132daec326565036bc8e8d1876f77ec183a7bd6",
"reference": "8132daec326565036bc8e8d1876f77ec183a7bd6",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/d13c43dbd4b791f815215959105a008515d1a2e0",
"reference": "d13c43dbd4b791f815215959105a008515d1a2e0",
"shasum": ""
},
"require": {
@ -3268,7 +3195,7 @@
},
"require-dev": {
"phpspec/phpspec": "^3.4",
"phpunit/phpunit": "^5.7.10"
"phpunit/phpunit": "^5.7.26"
},
"suggest": {
"ext-fileinfo": "Required for MimeType",
@ -3327,7 +3254,7 @@
"sftp",
"storage"
],
"time": "2020-01-04T16:30:31+00:00"
"time": "2020-02-05T18:14:17+00:00"
},
{
"name": "league/flysystem-aws-s3-v3",
@ -6041,16 +5968,16 @@
},
{
"name": "symfony/console",
"version": "v4.4.3",
"version": "v4.4.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "e9ee09d087e2c88eaf6e5fc0f5c574f64d100e4f"
"reference": "f512001679f37e6a042b51897ed24a2f05eba656"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/e9ee09d087e2c88eaf6e5fc0f5c574f64d100e4f",
"reference": "e9ee09d087e2c88eaf6e5fc0f5c574f64d100e4f",
"url": "https://api.github.com/repos/symfony/console/zipball/f512001679f37e6a042b51897ed24a2f05eba656",
"reference": "f512001679f37e6a042b51897ed24a2f05eba656",
"shasum": ""
},
"require": {
@ -6113,11 +6040,11 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2020-01-10T21:54:01+00:00"
"time": "2020-01-25T12:44:29+00:00"
},
{
"name": "symfony/event-dispatcher",
"version": "v4.4.3",
"version": "v4.4.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
@ -6245,7 +6172,7 @@
},
{
"name": "symfony/finder",
"version": "v4.4.3",
"version": "v4.4.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
@ -6294,7 +6221,7 @@
},
{
"name": "symfony/inflector",
"version": "v5.0.3",
"version": "v5.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/inflector.git",
@ -6352,7 +6279,7 @@
},
{
"name": "symfony/options-resolver",
"version": "v4.4.3",
"version": "v4.4.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
@ -6581,7 +6508,7 @@
},
{
"name": "symfony/process",
"version": "v4.4.3",
"version": "v4.4.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
@ -6630,7 +6557,7 @@
},
{
"name": "symfony/property-access",
"version": "v4.4.3",
"version": "v4.4.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/property-access.git",
@ -6697,7 +6624,7 @@
},
{
"name": "symfony/serializer",
"version": "v4.4.3",
"version": "v4.4.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/serializer.git",
@ -6836,7 +6763,7 @@
},
{
"name": "symfony/stopwatch",
"version": "v5.0.3",
"version": "v5.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/stopwatch.git",
@ -6943,16 +6870,16 @@
},
{
"name": "symfony/validator",
"version": "v4.4.3",
"version": "v4.4.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/validator.git",
"reference": "2f3ec17a371cc56b3a2855b5eae0702f70611e81"
"reference": "eb3e15de5c63873ca6e2a88b56a029f7be4c5953"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/validator/zipball/2f3ec17a371cc56b3a2855b5eae0702f70611e81",
"reference": "2f3ec17a371cc56b3a2855b5eae0702f70611e81",
"url": "https://api.github.com/repos/symfony/validator/zipball/eb3e15de5c63873ca6e2a88b56a029f7be4c5953",
"reference": "eb3e15de5c63873ca6e2a88b56a029f7be4c5953",
"shasum": ""
},
"require": {
@ -7031,11 +6958,11 @@
],
"description": "Symfony Validator Component",
"homepage": "https://symfony.com",
"time": "2020-01-21T08:20:44+00:00"
"time": "2020-01-31T09:11:17+00:00"
},
{
"name": "symfony/yaml",
"version": "v5.0.3",
"version": "v5.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
@ -7143,16 +7070,16 @@
},
{
"name": "voku/portable-utf8",
"version": "5.4.38",
"version": "5.4.39",
"source": {
"type": "git",
"url": "https://github.com/voku/portable-utf8.git",
"reference": "0991729d5ca364078b00fe0e107f87ec0d53b0d7"
"reference": "e462e8985a80cbd927765fd7e09f52bb103c9797"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/voku/portable-utf8/zipball/0991729d5ca364078b00fe0e107f87ec0d53b0d7",
"reference": "0991729d5ca364078b00fe0e107f87ec0d53b0d7",
"url": "https://api.github.com/repos/voku/portable-utf8/zipball/e462e8985a80cbd927765fd7e09f52bb103c9797",
"reference": "e462e8985a80cbd927765fd7e09f52bb103c9797",
"shasum": ""
},
"require": {
@ -7213,7 +7140,7 @@
"utf-8",
"utf8"
],
"time": "2020-01-14T13:30:41+00:00"
"time": "2020-01-30T15:12:06+00:00"
},
{
"name": "webimpress/safe-writer",
@ -7821,21 +7748,22 @@
},
{
"name": "codeception/module-rest",
"version": "1.1.0",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/Codeception/module-rest.git",
"reference": "e6ef1cc7fcc20b392ed2fb73ad809c63dc609781"
"reference": "c86417af517bb1fb5b88550455d823a7c9fc167e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/module-rest/zipball/e6ef1cc7fcc20b392ed2fb73ad809c63dc609781",
"reference": "e6ef1cc7fcc20b392ed2fb73ad809c63dc609781",
"url": "https://api.github.com/repos/Codeception/module-rest/zipball/c86417af517bb1fb5b88550455d823a7c9fc167e",
"reference": "c86417af517bb1fb5b88550455d823a7c9fc167e",
"shasum": ""
},
"require": {
"codeception/codeception": "^4.0",
"flow/jsonpath": "^0.5",
"justinrainbow/json-schema": "^5.2.9",
"php": ">=5.6.0 <8.0"
},
"require-dev": {
@ -7867,7 +7795,7 @@
"codeception",
"rest"
],
"time": "2020-01-24T08:55:04+00:00"
"time": "2020-02-01T19:23:56+00:00"
},
{
"name": "codeception/phpunit-wrapper",
@ -8137,6 +8065,72 @@
],
"time": "2016-01-20T08:20:44+00:00"
},
{
"name": "justinrainbow/json-schema",
"version": "5.2.9",
"source": {
"type": "git",
"url": "https://github.com/justinrainbow/json-schema.git",
"reference": "44c6787311242a979fa15c704327c20e7221a0e4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4",
"reference": "44c6787311242a979fa15c704327c20e7221a0e4",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1",
"json-schema/json-schema-test-suite": "1.2.0",
"phpunit/phpunit": "^4.8.35"
},
"bin": [
"bin/validate-json"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0.x-dev"
}
},
"autoload": {
"psr-4": {
"JsonSchema\\": "src/JsonSchema/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bruno Prieto Reis",
"email": "bruno.p.reis@gmail.com"
},
{
"name": "Justin Rainbow",
"email": "justin.rainbow@gmail.com"
},
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch"
},
{
"name": "Robert Schönthal",
"email": "seroscho@googlemail.com"
}
],
"description": "A library to validate a json schema.",
"homepage": "https://github.com/justinrainbow/json-schema",
"keywords": [
"json",
"schema"
],
"time": "2019-09-25T14:49:45+00:00"
},
{
"name": "mockery/mockery",
"version": "1.3.1",
@ -9678,12 +9672,12 @@
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "666ba252853924887ac57dc9f66e6b6af78d5a76"
"reference": "af61943caaa512a4f00f1ee80e6e0cfec3fb63d1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/666ba252853924887ac57dc9f66e6b6af78d5a76",
"reference": "666ba252853924887ac57dc9f66e6b6af78d5a76",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/af61943caaa512a4f00f1ee80e6e0cfec3fb63d1",
"reference": "af61943caaa512a4f00f1ee80e6e0cfec3fb63d1",
"shasum": ""
},
"conflict": {
@ -9756,6 +9750,7 @@
"monolog/monolog": ">=1.8,<1.12",
"namshi/jose": "<2.2",
"onelogin/php-saml": "<2.10.4",
"oneup/uploader-bundle": ">=1,<1.9.3|>=2,<2.1.5",
"openid/php-openid": "<2.3",
"oro/crm": ">=1.7,<1.7.4",
"oro/platform": ">=1.7,<1.7.4",
@ -9765,7 +9760,7 @@
"paypal/merchant-sdk-php": "<3.12",
"pear/archive_tar": "<1.4.4",
"phpmailer/phpmailer": ">=5,<5.2.27|>=6,<6.0.6",
"phpoffice/phpexcel": "<=1.8.1",
"phpoffice/phpexcel": "<1.8.2",
"phpoffice/phpspreadsheet": "<=1.5",
"phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3",
"phpwhois/phpwhois": "<=4.2.5",
@ -9779,12 +9774,17 @@
"sensiolabs/connect": "<4.2.3",
"serluck/phpwhois": "<=4.2.6",
"shopware/shopware": "<5.3.7",
"silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1",
"silverstripe/assets": ">=1,<1.3.5",
"silverstripe/cms": ">=3,<=3.0.11|>=3.1,<3.1.11",
"silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1",
"silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3",
"silverstripe/framework": ">=3,<3.6.7|>=3.7,<3.7.3|>=4,<4.4",
"silverstripe/framework": ">=3,<3.9.99|>=4,<4.4.4",
"silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2",
"silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1",
"silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4",
"silverstripe/subsites": ">=2,<2.1.1",
"silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1",
"silverstripe/userforms": "<3",
"simple-updates/phpwhois": "<=1",
"simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4",
@ -9803,6 +9803,7 @@
"sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1",
"sylius/resource-bundle": ">=1,<1.3.13|>=1.4,<1.4.6|>=1.5,<1.5.1|>=1.6,<1.6.3",
"sylius/sylius": ">=1,<1.3.12|>=1.4,<1.4.4",
"symbiote/silverstripe-multivaluefield": ">=3,<3.0.99",
"symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8",
"symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7",
"symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1",
@ -9896,7 +9897,7 @@
}
],
"description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it",
"time": "2020-01-28T17:25:41+00:00"
"time": "2020-02-05T14:02:42+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
@ -10515,16 +10516,16 @@
},
{
"name": "squizlabs/php_codesniffer",
"version": "3.5.3",
"version": "3.5.4",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb"
"reference": "dceec07328401de6211037abbb18bda423677e26"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/557a1fc7ac702c66b0bbfe16ab3d55839ef724cb",
"reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dceec07328401de6211037abbb18bda423677e26",
"reference": "dceec07328401de6211037abbb18bda423677e26",
"shasum": ""
},
"require": {
@ -10562,11 +10563,11 @@
"phpcs",
"standards"
],
"time": "2019-12-04T04:46:47+00:00"
"time": "2020-01-30T22:20:29+00:00"
},
{
"name": "symfony/browser-kit",
"version": "v5.0.3",
"version": "v5.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
@ -10625,7 +10626,7 @@
},
{
"name": "symfony/css-selector",
"version": "v5.0.3",
"version": "v5.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
@ -10678,7 +10679,7 @@
},
{
"name": "symfony/dom-crawler",
"version": "v5.0.3",
"version": "v5.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
@ -10829,7 +10830,6 @@
"aliases": [],
"minimum-stability": "dev",
"stability-flags": {
"azuracast/azuracore": 20,
"azuracast/azuraforms": 20,
"azuracast/nowplaying": 20,
"bernard/bernard": 20,

View File

@ -1,8 +1,8 @@
<?php
use App\Console\Command;
use Azura\Console\Application;
use Azura\Settings;
use App\Console\Application;
use App\Settings;
return function (Application $console) {
// Set console version and name.

View File

@ -1,15 +1,79 @@
<?php
use App\Middleware;
use App\Console\Command;
return function (\Azura\EventDispatcher $dispatcher)
{
// Build default routes and middleware
$dispatcher->addListener(Azura\Event\BuildRoutes::class, function(Azura\Event\BuildRoutes $event) {
use App\Console\Command;
use App\Event;
use App\Middleware;
use App\Settings;
return function (\App\EventDispatcher $dispatcher) {
$dispatcher->addListener(Event\BuildConsoleCommands::class, function (Event\BuildConsoleCommands $event) {
$console = $event->getConsole();
$di = $console->getContainer();
/** @var Settings $settings */
$settings = $di->get(Settings::class);
if ($settings->enableRedis()) {
$console->command('cache:clear', Command\ClearCacheCommand::class)
->setDescription('Clear all application caches.');
}
if ($settings->enableDatabase()) {
// Doctrine ORM/DBAL
Doctrine\ORM\Tools\Console\ConsoleRunner::addCommands($console);
// Add Doctrine Migrations
$defaults = [
'table_name' => 'app_migrations',
'directory' => $settings[Settings::BASE_DIR] . '/src/Entity/Migration',
'namespace' => 'App\Entity\Migration',
];
$user_options = $settings[Settings::DOCTRINE_OPTIONS]['migrations'] ?? [];
$options = array_merge($defaults, $user_options);
/** @var Doctrine\ORM\EntityManager $em */
$em = $di->get(Doctrine\ORM\EntityManager::class);
$connection = $em->getConnection();
$helper_set = $console->getHelperSet();
$doctrine_helpers = Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($em);
$helper_set->set($doctrine_helpers->get('db'), 'db');
$helper_set->set($doctrine_helpers->get('em'), 'em');
$migrate_config = new Doctrine\Migrations\Configuration\Configuration($connection);
$migrate_config->setMigrationsTableName($options['table_name']);
$migrate_config->setMigrationsDirectory($options['directory']);
$migrate_config->setMigrationsNamespace($options['namespace']);
$migrate_config_helper = new Doctrine\Migrations\Tools\Console\Helper\ConfigurationHelper($connection,
$migrate_config);
$helper_set->set($migrate_config_helper, 'configuration');
Doctrine\Migrations\Tools\Console\ConsoleRunner::addCommands($console);
}
if (file_exists(__DIR__ . '/cli.php')) {
call_user_func(include(__DIR__ . '/cli.php'), $console);
}
});
$dispatcher->addListener(Event\BuildRoutes::class, function (Event\BuildRoutes $event) {
$app = $event->getApp();
if (file_exists(__DIR__.'/routes.dev.php')) {
$dev_routes = require __DIR__.'/routes.dev.php';
// Load app-specific route configuration.
$container = $app->getContainer();
/** @var Settings $settings */
$settings = $container->get(Settings::class);
if (file_exists(__DIR__ . '/routes.php')) {
call_user_func(include(__DIR__ . '/routes.php'), $app);
}
if (file_exists(__DIR__ . '/routes.dev.php')) {
$dev_routes = require __DIR__ . '/routes.dev.php';
$dev_routes($app);
}
@ -17,16 +81,34 @@ return function (\Azura\EventDispatcher $dispatcher)
$app->add(Middleware\InjectAcl::class);
$app->add(Middleware\GetCurrentUser::class);
}, 2);
// Request injection middlewares.
$app->add(Middleware\InjectRouter::class);
$app->add(Middleware\InjectRateLimit::class);
// System middleware for routing and body parsing.
$app->addBodyParsingMiddleware();
$app->addRoutingMiddleware();
// Redirects and updates that should happen before system middleware.
$app->add(new Middleware\RemoveSlashes);
$app->add(new Middleware\ApplyXForwardedProto);
// Error handling, which should always be near the "last" element.
$errorMiddleware = $app->addErrorMiddleware(!$settings->isProduction(), true, true);
$errorMiddleware->setDefaultErrorHandler(Slim\Interfaces\ErrorHandlerInterface::class);
// Use PSR-7 compatible sessions.
$app->add(Middleware\InjectSession::class);
});
// Build default menus
$dispatcher->addListener(App\Event\BuildAdminMenu::class, function(\App\Event\BuildAdminMenu $e) {
$callable = require(__DIR__.'/menus/admin.php');
$dispatcher->addListener(App\Event\BuildAdminMenu::class, function (\App\Event\BuildAdminMenu $e) {
$callable = require(__DIR__ . '/menus/admin.php');
$callable($e);
});
$dispatcher->addListener(App\Event\BuildStationMenu::class, function(\App\Event\BuildStationMenu $e) {
$callable = require(__DIR__.'/menus/station.php');
$dispatcher->addListener(App\Event\BuildStationMenu::class, function (\App\Event\BuildStationMenu $e) {
$callable = require(__DIR__ . '/menus/station.php');
$callable($e);
});

View File

@ -71,7 +71,7 @@ return [
[
'label' => __('Time Zone'),
'description' => __('Scheduled playlists and other timed items will be controlled by this time zone.'),
'options' => \Azura\Timezone::fetchSelect(),
'options' => \App\Timezone::fetchSelect(),
'default' => \App\Customization::DEFAULT_TIMEZONE,
'form_group_class' => 'col-sm-12',
]

View File

@ -5,7 +5,7 @@ use App\Controller;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Middleware;
use Azura\Middleware as AzuraMiddleware;
use App\Middleware as AzuraMiddleware;
use Slim\App;
use Slim\Routing\RouteCollectorProxy;

View File

@ -3,43 +3,115 @@
* PHP-DI Services
*/
use App;
use App\Settings;
use Doctrine\ORM\EntityManager;
use Psr\Container\ContainerInterface;
return [
return array_merge(
include(__DIR__ . '/services/cache.php'),
include(__DIR__ . '/services/database.php'),
include(__DIR__ . '/services/http.php'),
include(__DIR__ . '/services/view.php'), [
/*
* Slim Component Overrides
*/
// URL Router helper
App\Http\Router::class => function (
Settings $settings,
\Slim\App $app,
App\Entity\Repository\SettingsRepository $settingsRepo
) {
$route_parser = $app->getRouteCollector()->getRouteParser();
return new App\Http\Router($settings, $route_parser, $settingsRepo);
// Configuration management
App\Config::class => function (App\Settings $settings) {
return new App\Config($settings[App\Settings::CONFIG_DIR]);
},
Azura\Http\RouterInterface::class => DI\Get(App\Http\Router::class),
// Error Handler
App\Http\ErrorHandler::class => DI\autowire(),
Slim\Interfaces\ErrorHandlerInterface::class => DI\Get(App\Http\ErrorHandler::class),
// Console
App\Console\Application::class => function (DI\Container $di, App\EventDispatcher $dispatcher) {
$console = new App\Console\Application('Command Line Interface', '1.0.0', $di);
/*
* Doctrine Database
*/
// Trigger an event for the core app and all plugins to build their CLI commands.
$event = new App\Event\BuildConsoleCommands($console);
$dispatcher->dispatch($event);
EntityManager::class => DI\decorate(function (EntityManager $em, ContainerInterface $di) {
$event_manager = $em->getEventManager();
$event_manager->addEventSubscriber($di->get(App\Doctrine\Event\StationRequiresRestart::class));
$event_manager->addEventSubscriber($di->get(App\Doctrine\Event\AuditLog::class));
return $console;
},
return $em;
}),
// Event Dispatcher
App\EventDispatcher::class => function (Slim\App $app, App\Plugins $plugins) {
$dispatcher = new App\EventDispatcher($app->getCallableResolver());
// Register application default events.
if (file_exists(__DIR__ . '/events.php')) {
call_user_func(include(__DIR__ . '/events.php'), $dispatcher);
}
// Register plugin-provided events.
$plugins->registerEvents($dispatcher);
return $dispatcher;
},
// Monolog Logger
Monolog\Logger::class => function (App\Settings $settings) {
$logger = new Monolog\Logger($settings[App\Settings::APP_NAME] ?? 'app');
$logging_level = $settings->isProduction() ? Psr\Log\LogLevel::INFO : Psr\Log\LogLevel::DEBUG;
if ($settings[App\Settings::IS_DOCKER] || $settings[App\Settings::IS_CLI]) {
$log_stderr = new Monolog\Handler\StreamHandler('php://stderr', $logging_level, true);
$logger->pushHandler($log_stderr);
}
$log_file = new Monolog\Handler\StreamHandler($settings[App\Settings::TEMP_DIR] . '/app.log',
$logging_level, true);
$logger->pushHandler($log_file);
return $logger;
},
Psr\Log\LoggerInterface::class => DI\get(Monolog\Logger::class),
// Middleware
App\Middleware\InjectRateLimit::class => DI\autowire(),
App\Middleware\InjectRouter::class => DI\autowire(),
App\Middleware\InjectSession::class => DI\autowire(),
App\Middleware\EnableView::class => DI\autowire(),
// Rate limiter
App\RateLimit::class => DI\autowire(),
// Doctrine annotations reader
Doctrine\Common\Annotations\Reader::class => function (
Doctrine\Common\Cache\Cache $doctrine_cache,
App\Settings $settings
) {
return new Doctrine\Common\Annotations\CachedReader(
new Doctrine\Common\Annotations\AnnotationReader,
$doctrine_cache,
!$settings->isProduction()
);
},
// Symfony Serializer
Symfony\Component\Serializer\Serializer::class => function (
Doctrine\Common\Annotations\Reader $annotation_reader,
Doctrine\ORM\EntityManager $em
) {
$meta_factory = new Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory(
new Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader($annotation_reader)
);
$normalizers = [
new Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer(),
new App\Normalizer\DoctrineEntityNormalizer($em, $annotation_reader, $meta_factory),
new Symfony\Component\Serializer\Normalizer\ObjectNormalizer($meta_factory),
];
return new Symfony\Component\Serializer\Serializer($normalizers);
},
// Symfony Validator
Symfony\Component\Validator\ConstraintValidatorFactoryInterface::class => DI\autowire(App\Validator\ConstraintValidatorFactory::class),
Symfony\Component\Validator\Validator\ValidatorInterface::class => function (
Doctrine\Common\Annotations\Reader $annotation_reader,
Symfony\Component\Validator\ConstraintValidatorFactoryInterface $cvf
) {
$builder = new Symfony\Component\Validator\ValidatorBuilder();
$builder->setConstraintValidatorFactory($cvf);
$builder->enableAnnotationMapping($annotation_reader);
return $builder->getValidator();
},
App\Doctrine\Event\AuditLog::class => DI\autowire(),
App\Doctrine\Event\StationRequiresRestart::class => DI\autowire(),
@ -61,66 +133,6 @@ return [
App\Entity\Repository\StationStreamerRepository::class => DI\autowire(),
App\Entity\Repository\UserRepository::class => DI\autowire(),
/*
* View
*/
Azura\View::class => DI\decorate(function (Azura\View $view, ContainerInterface $di) {
$view->registerFunction('mailto', function ($address, $link_text = null) {
$address = substr(chunk_split(bin2hex(" $address"), 2, ";&#x"), 3, -3);
$link_text = $link_text ?? $address;
return '<a href="mailto:' . $address . '">' . $link_text . '</a>';
});
$view->registerFunction('pluralize', function ($word, $num = 0) {
if ((int)$num === 1) {
return $word;
}
return Doctrine\Common\Inflector\Inflector::pluralize($word);
});
$view->registerFunction('truncate', function ($text, $length = 80) {
return App\Utilities::truncateText($text, $length);
});
$view->registerFunction('truncateUrl', function ($url) {
return App\Utilities::truncateUrl($url);
});
$view->registerFunction('link', function ($url, $external = true, $truncate = true) {
$url = htmlspecialchars($url, \ENT_QUOTES, 'UTF-8');
$a = ['href="' . $url . '"'];
if ($external) {
$a[] = 'target="_blank"';
}
$a_body = ($truncate) ? App\Utilities::truncateUrl($url) : $url;
return '<a ' . implode(' ', $a) . '>' . $a_body . '</a>';
});
$view->addData([
'assets' => $di->get(Azura\Assets::class),
'auth' => $di->get(App\Auth::class),
'acl' => $di->get(App\Acl::class),
'customization' => $di->get(App\Customization::class),
'version' => $di->get(App\Version::class),
]);
return $view;
}),
/*
* Event Dispatcher
*/
Azura\EventDispatcher::class => DI\decorate(function (Azura\EventDispatcher $dispatcher, ContainerInterface $di) {
if ($di->has(App\Plugins::class)) {
/** @var App\Plugins $plugins */
$plugins = $di->get(App\Plugins::class);
// Register plugin-provided events.
$plugins->registerEvents($dispatcher);
}
return $dispatcher;
}),
/*
* AzuraCast-specific dependencies
*/
@ -139,7 +151,7 @@ return [
// Message queue manager class
App\MessageQueue::class => function (
\Redis $redis,
Redis $redis,
ContainerInterface $di,
Monolog\Logger $logger,
EntityManager $em
@ -206,22 +218,22 @@ return [
$supervisor = new Supervisor\Supervisor($connector);
if (!$supervisor->isConnected()) {
throw new \Azura\Exception(sprintf('Could not connect to supervisord.'));
throw new \App\Exception(sprintf('Could not connect to supervisord.'));
}
return $supervisor;
},
Azura\Assets::class => function (Azura\Config $config, Settings $settings) {
App\Assets::class => function (App\Config $config, Settings $settings) {
$libraries = $config->get('assets');
$versioned_files = [];
$assets_file = $settings[Settings::BASE_DIR] . '/web/static/assets.json';
if (file_exists($assets_file)) {
$versioned_files = json_decode(file_get_contents($assets_file), true);
$versioned_files = json_decode(file_get_contents($assets_file), true, 512, JSON_THROW_ON_ERROR);
}
return new Azura\Assets($libraries, $versioned_files);
return new App\Assets($libraries, $versioned_files);
},
/*
@ -302,7 +314,7 @@ return [
App\Webhook\Dispatcher::class => function (
ContainerInterface $di,
Azura\Config $config,
App\Config $config,
Monolog\Logger $logger
) {
$webhooks = $config->get('webhooks');
@ -365,4 +377,4 @@ return [
'App\Controller\Stations\*Controller' => DI\autowire(),
'App\Controller\Stations\Files\*Controller' => DI\autowire(),
'App\Controller\Stations\Reports\*Controller' => DI\autowire(),
];
]);

45
config/services/cache.php Normal file
View File

@ -0,0 +1,45 @@
<?php
return [
// Cache
Psr\Cache\CacheItemPoolInterface::class => function (App\Settings $settings, Psr\Container\ContainerInterface $di) {
// Never use the Redis cache for CLI commands, as the CLI commands are where
// the Redis cache gets flushed, so this will lead to a race condition that can't
// be solved within the application.
return $settings->enableRedis() && !$settings->isCli()
? new Cache\Adapter\Redis\RedisCachePool($di->get(Redis::class))
: new Cache\Adapter\PHPArray\ArrayCachePool;
},
Psr\SimpleCache\CacheInterface::class => DI\get(Psr\Cache\CacheItemPoolInterface::class),
// Doctrine cache
Doctrine\Common\Cache\Cache::class => function (Psr\Cache\CacheItemPoolInterface $cachePool) {
return new Cache\Bridge\Doctrine\DoctrineCacheBridge(new Cache\Prefixed\PrefixedCachePool($cachePool,
'doctrine|'));
},
// Session save handler middleware
Mezzio\Session\SessionPersistenceInterface::class => function (Cache\Adapter\Redis\RedisCachePool $redisPool) {
return new Mezzio\Session\Cache\CacheSessionPersistence(
new Cache\Prefixed\PrefixedCachePool($redisPool, 'session|'),
'app_session',
'/',
'nocache',
43200,
time()
);
},
// Redis cache
Redis::class => function (App\Settings $settings) {
$redis_host = $settings[App\Settings::IS_DOCKER] ? 'redis' : 'localhost';
$redis = new Redis();
$redis->connect($redis_host, 6379, 15);
$redis->select(1);
return $redis;
},
];

View File

@ -0,0 +1,95 @@
<?php
return [
// DBAL
Doctrine\DBAL\Connection::class => function (Doctrine\ORM\EntityManager $em) {
return $em->getConnection();
},
'db' => DI\Get(Doctrine\DBAL\Connection::class),
// Doctrine Entity Manager
Doctrine\ORM\EntityManager::class => function (
Doctrine\Common\Cache\Cache $doctrine_cache,
Doctrine\Common\Annotations\Reader $reader,
App\Settings $settings,
App\Doctrine\Event\StationRequiresRestart $eventRequiresRestart,
App\Doctrine\Event\AuditLog $eventAuditLog
) {
$defaults = [
'cache' => $doctrine_cache,
'autoGenerateProxies' => !$settings->isProduction(),
'proxyNamespace' => 'AppProxy',
'proxyPath' => $settings->getTempDirectory() . '/proxies',
'modelPath' => $settings->getBaseDirectory() . '/src/Entity',
'useSimpleAnnotations' => false,
'conn' => [
'host' => $_ENV['MYSQL_HOST'] ?? 'mariadb',
'port' => $_ENV['MYSQL_PORT'] ?? 3306,
'dbname' => $_ENV['MYSQL_DATABASE'],
'user' => $_ENV['MYSQL_USER'],
'password' => $_ENV['MYSQL_PASSWORD'],
'driver' => 'pdo_mysql',
'charset' => 'utf8mb4',
'defaultTableOptions' => [
'charset' => 'utf8mb4',
'collate' => 'utf8mb4_general_ci',
],
'driverOptions' => [
// PDO::MYSQL_ATTR_INIT_COMMAND = 1002;
1002 => 'SET NAMES utf8mb4 COLLATE utf8mb4_general_ci',
],
'platform' => new Doctrine\DBAL\Platforms\MariaDb1027Platform(),
],
];
if (!$settings[App\Settings::IS_DOCKER]) {
$defaults['conn']['host'] = $_ENV['db_host'] ?? 'localhost';
$defaults['conn']['port'] = $_ENV['db_port'] ?? '3306';
$defaults['conn']['dbname'] = $_ENV['db_name'] ?? 'app';
$defaults['conn']['user'] = $_ENV['db_username'] ?? 'app';
$defaults['conn']['password'] = $_ENV['db_password'];
}
$app_options = $settings[App\Settings::DOCTRINE_OPTIONS] ?? [];
$options = array_merge($defaults, $app_options);
try {
// Fetch and store entity manager.
$config = new Doctrine\ORM\Configuration;
if ($options['useSimpleAnnotations']) {
$metadata_driver = $config->newDefaultAnnotationDriver((array)$options['modelPath'],
$options['useSimpleAnnotations']);
} else {
$metadata_driver = new Doctrine\ORM\Mapping\Driver\AnnotationDriver(
$reader,
(array)$options['modelPath']
);
}
$config->setMetadataDriverImpl($metadata_driver);
$config->setMetadataCacheImpl($options['cache']);
$config->setQueryCacheImpl($options['cache']);
$config->setResultCacheImpl($options['cache']);
$config->setProxyDir($options['proxyPath']);
$config->setProxyNamespace($options['proxyNamespace']);
$config->setAutoGenerateProxyClasses(Doctrine\Common\Proxy\AbstractProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS);
if (isset($options['conn']['debug']) && $options['conn']['debug']) {
$config->setSQLLogger(new Doctrine\DBAL\Logging\EchoSQLLogger);
}
$config->addCustomNumericFunction('RAND', App\Doctrine\Functions\Rand::class);
$eventManager = new Doctrine\Common\EventManager;
$eventManager->addEventSubscriber($eventRequiresRestart);
$eventManager->addEventSubscriber($eventAuditLog);
return Doctrine\ORM\EntityManager::create($options['conn'], $config, $eventManager);
} catch (Exception $e) {
throw new App\Exception\BootstrapException($e->getMessage());
}
},
'em' => DI\Get(Doctrine\ORM\EntityManager::class),
];

46
config/services/http.php Normal file
View File

@ -0,0 +1,46 @@
<?php
use App\Settings;
return [
// URL Router helper
App\Http\Router::class => function (
Settings $settings,
Slim\App $app,
App\Entity\Repository\SettingsRepository $settingsRepo
) {
$route_parser = $app->getRouteCollector()->getRouteParser();
return new App\Http\Router($settings, $route_parser, $settingsRepo);
},
App\Http\RouterInterface::class => DI\Get(App\Http\Router::class),
// Error handler
App\Http\ErrorHandler::class => DI\autowire(),
Slim\Interfaces\ErrorHandlerInterface::class => DI\Get(App\Http\ErrorHandler::class),
// HTTP client
GuzzleHttp\Client::class => function (Psr\Log\LoggerInterface $logger) {
$stack = GuzzleHttp\HandlerStack::create();
$stack->unshift(function (callable $handler) {
return function (Psr\Http\Message\RequestInterface $request, array $options) use ($handler) {
$options[GuzzleHttp\RequestOptions::VERIFY] = Composer\CaBundle\CaBundle::getSystemCaRootBundlePath();
return $handler($request, $options);
};
}, 'ssl_verify');
$stack->push(GuzzleHttp\Middleware::log(
$logger,
new GuzzleHttp\MessageFormatter('HTTP client {method} call to {uri} produced response {code}'),
Monolog\Logger::DEBUG
));
return new GuzzleHttp\Client([
'handler' => $stack,
GuzzleHttp\RequestOptions::HTTP_ERRORS => false,
GuzzleHttp\RequestOptions::TIMEOUT => 3.0,
]);
},
];

65
config/services/view.php Normal file
View File

@ -0,0 +1,65 @@
<?php
return [
// View (Plates Templates)
App\View::class => function (
Psr\Container\ContainerInterface $di,
App\Settings $settings,
App\Http\RouterInterface $router,
App\EventDispatcher $dispatcher
) {
$view = new App\View($settings[App\Settings::VIEWS_DIR], 'phtml');
$view->registerFunction('service', function ($service) use ($di) {
return $di->get($service);
});
$view->registerFunction('escapeJs', function ($string) {
return json_encode($string, JSON_THROW_ON_ERROR, 512);
});
$view->addData([
'settings' => $settings,
'router' => $router,
'assets' => $di->get(App\Assets::class),
'auth' => $di->get(App\Auth::class),
'acl' => $di->get(App\Acl::class),
'customization' => $di->get(App\Customization::class),
'version' => $di->get(App\Version::class),
]);
$view->registerFunction('mailto', function ($address, $link_text = null) {
$address = substr(chunk_split(bin2hex(" $address"), 2, ';&#x'), 3, -3);
$link_text = $link_text ?? $address;
return '<a href="mailto:' . $address . '">' . $link_text . '</a>';
});
$view->registerFunction('pluralize', function ($word, $num = 0) {
if ((int)$num === 1) {
return $word;
}
return Doctrine\Common\Inflector\Inflector::pluralize($word);
});
$view->registerFunction('truncate', function ($text, $length = 80) {
return App\Utilities::truncateText($text, $length);
});
$view->registerFunction('truncateUrl', function ($url) {
return App\Utilities::truncateUrl($url);
});
$view->registerFunction('link', function ($url, $external = true, $truncate = true) {
$url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
$a = ['href="' . $url . '"'];
if ($external) {
$a[] = 'target="_blank"';
}
$a_body = ($truncate) ? App\Utilities::truncateUrl($url) : $url;
return '<a ' . implode(' ', $a) . '>' . $a_body . '</a>';
});
$dispatcher->dispatch(new App\Event\BuildView($view));
return $view;
},
];

View File

@ -7,8 +7,8 @@ parameters:
bootstrap: %rootDir%/../../../util/phpstan.php
universalObjectCratesClasses:
- Azura\Session\NamespaceInterface
- Azura\View
- App\Session\NamespaceInterface
- App\View
ignoreErrors:
# Caused by Symfony Validator (perhaps wrongly) returning the interface.

30
src/App.php Normal file
View File

@ -0,0 +1,30 @@
<?php
namespace App;
use App\Http\Factory\ServerRequestFactory;
use Psr\Http\Message\ServerRequestInterface;
use Slim\App as SlimApp;
class App extends SlimApp
{
/**
* @inheritDoc
*/
public function run(?ServerRequestInterface $request = null): void
{
if (!$request) {
$request = $this->createServerRequest();
}
parent::run($request);
}
/**
* @return ServerRequestInterface
*/
public function createServerRequest(): ServerRequestInterface
{
$requestCreator = new ServerRequestFactory;
return $requestCreator->createServerRequestFromGlobals();
}
}

View File

@ -1,18 +1,22 @@
<?php
namespace App;
use App\Http\Factory\ResponseFactory;
use App\Http\Factory\ServerRequestFactory;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\App;
use Azura\Exception;
use Azura\Http\Factory\ResponseFactory;
use Azura\Http\Factory\ServerRequestFactory;
use Azura\Logger;
use DI;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Invoker;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Log\LoggerInterface;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\MiddlewareDispatcherInterface;
use Slim\Interfaces\RouteCollectorInterface;
use Slim\Interfaces\RouteResolverInterface;
class AppFactory extends \Azura\AppFactory
class AppFactory
{
/**
* @inheritDoc
@ -34,7 +38,6 @@ class AppFactory extends \Azura\AppFactory
// Override DI definitions for settings.
$diDefinitions[Settings::class] = $settings;
$diDefinitions[\Azura\Settings::class] = DI\get(Settings::class);
$diDefinitions['settings'] = DI\get(Settings::class);
self::applyPhpSettings($settings);
@ -81,6 +84,176 @@ class AppFactory extends \Azura\AppFactory
$settings[Settings::CONFIG_DIR] = $settings[Settings::BASE_DIR] . '/config';
$settings[Settings::VIEWS_DIR] = $settings[Settings::BASE_DIR] . '/templates';
return parent::buildSettings($settings);
if (!isset($settings[Settings::BASE_DIR])) {
throw new Exception\BootstrapException('No base directory specified!');
}
if (!isset($settings[Settings::TEMP_DIR])) {
$settings[Settings::TEMP_DIR] = dirname($settings[Settings::BASE_DIR]) . '/www_tmp';
}
if (!isset($settings[Settings::CONFIG_DIR])) {
$settings[Settings::CONFIG_DIR] = $settings[Settings::BASE_DIR] . '/config';
}
if (!isset($settings[Settings::VIEWS_DIR])) {
$settings[Settings::VIEWS_DIR] = $settings[Settings::BASE_DIR] . '/templates';
}
if ($settings[Settings::IS_DOCKER]) {
$_ENV = getenv();
} elseif (file_exists($settings[Settings::BASE_DIR] . '/env.ini')) {
$_ENV = array_merge($_ENV, parse_ini_file($settings[Settings::BASE_DIR] . '/env.ini'));
}
if (!isset($settings[Settings::APP_ENV])) {
$settings[Settings::APP_ENV] = $_ENV['APPLICATION_ENV'] ?? Settings::ENV_PRODUCTION;
}
if (isset($_ENV['BASE_URL'])) {
$settings[Settings::BASE_URL] = $_ENV['BASE_URL'];
}
if (file_exists($settings[Settings::CONFIG_DIR] . '/settings.php')) {
$settingsFile = require($settings[Settings::CONFIG_DIR] . '/settings.php');
if (is_array($settingsFile)) {
$settings = array_merge($settings, $settingsFile);
}
}
return $settings;
}
/**
* @param Settings $settings
*/
protected static function applyPhpSettings(Settings $settings): void
{
ini_set('display_startup_errors', !$settings->isProduction() ? 1 : 0);
ini_set('display_errors', !$settings->isProduction() ? 1 : 0);
ini_set('log_errors', 1);
ini_set('error_log',
$settings[Settings::IS_DOCKER] ? '/dev/stderr' : $settings[Settings::TEMP_DIR] . '/php_errors.log');
ini_set('error_reporting', E_ALL & ~E_NOTICE & ~E_WARNING & ~E_STRICT);
ini_set('session.use_only_cookies', 1);
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_lifetime', 86400);
ini_set('session.use_strict_mode', 1);
session_cache_limiter('');
}
/**
* @param Settings $settings
* @param array $diDefinitions
*
* @return DI\Container
* @throws \Exception
*/
protected static function buildContainer(Settings $settings, array $diDefinitions = []): DI\Container
{
$containerBuilder = new DI\ContainerBuilder;
$containerBuilder->useAnnotations(true);
$containerBuilder->useAutowiring(true);
if ($settings->isProduction()) {
$containerBuilder->enableCompilation($settings[Settings::TEMP_DIR]);
}
if (!isset($diDefinitions[Settings::class])) {
$diDefinitions[Settings::class] = $settings;
$diDefinitions['settings'] = DI\Get(Settings::class);
}
$containerBuilder->addDefinitions($diDefinitions);
// Check for services.php file and include it if one exists.
$config_dir = $settings[Settings::CONFIG_DIR];
if (file_exists($config_dir . '/services.php')) {
$containerBuilder->addDefinitions($config_dir . '/services.php');
}
return $containerBuilder->build();
}
/**
* @param ContainerInterface $container
*
* @return \App\App
*/
protected static function createFromContainer(ContainerInterface $container): App
{
$responseFactory = $container->has(ResponseFactoryInterface::class)
? $container->get(ResponseFactoryInterface::class)
: new Http\Factory\ResponseFactory;
$callableResolver = $container->has(CallableResolverInterface::class)
? $container->get(CallableResolverInterface::class)
: null;
$routeCollector = $container->has(RouteCollectorInterface::class)
? $container->get(RouteCollectorInterface::class)
: null;
$routeResolver = $container->has(RouteResolverInterface::class)
? $container->get(RouteResolverInterface::class)
: null;
$middlewareDispatcher = $container->has(MiddlewareDispatcherInterface::class)
? $container->get(MiddlewareDispatcherInterface::class)
: null;
return new App(
$responseFactory,
$container,
$callableResolver,
$routeCollector,
$routeResolver,
$middlewareDispatcher
);
}
/**
* @param App $app
*/
protected static function updateRouteHandling(App $app): void
{
$di = $app->getContainer();
$routeCollector = $app->getRouteCollector();
/** @var Settings $settings */
$settings = $di->get(Settings::class);
// Use the PHP-DI Bridge's action invocation helper.
$resolvers = [
// Inject parameters by name first
new Invoker\ParameterResolver\AssociativeArrayResolver(),
// Then inject services by type-hints for those that weren't resolved
new Invoker\ParameterResolver\Container\TypeHintContainerResolver($di),
// Then fall back on parameters default values for optional route parameters
new Invoker\ParameterResolver\DefaultValueResolver(),
];
$invoker = new Invoker\Invoker(new Invoker\ParameterResolver\ResolverChain($resolvers), $di);
$controllerInvoker = new DI\Bridge\Slim\ControllerInvoker($invoker);
$routeCollector->setDefaultInvocationStrategy($controllerInvoker);
if ($settings->isProduction()) {
$routeCollector->setCacheFile($settings[Settings::TEMP_DIR] . '/app_routes.cache.php');
}
}
/**
* @param App $app
*/
protected static function buildRoutes(App $app): void
{
$di = $app->getContainer();
/** @var EventDispatcher $dispatcher */
$dispatcher = $di->get(EventDispatcher::class);
$dispatcher->dispatch(new Event\BuildRoutes($app));
}
}

435
src/Assets.php Normal file
View File

@ -0,0 +1,435 @@
<?php
namespace App;
use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use function base64_encode;
use function is_array;
use function is_callable;
use function preg_replace;
use function random_bytes;
/**
* Asset management helper class.
* Inspired by Asseter by Adam Banaszkiewicz: https://github.com/requtize
* @link https://github.com/requtize/assetter
*/
class Assets
{
/** @var array Known libraries loaded in initialization. */
protected $libraries = [];
/** @var array An optional array lookup for versioned files. */
protected $versioned_files = [];
/** @var array Loaded libraries. */
protected $loaded = [];
/** @var bool Whether the current loaded libraries have been sorted by order. */
protected $is_sorted = true;
/** @var string A randomly generated number-used-once (nonce) for inline CSP. */
protected $csp_nonce;
/** @var array The loaded domains that should be included in the CSP header. */
protected $csp_domains;
/**
* Assets constructor.
*
* @param array $libraries
* @param array $versioned_files
*
* @throws \Exception
*/
public function __construct(array $libraries = [], array $versioned_files = [])
{
foreach ($libraries as $library_name => $library) {
$this->addLibrary($library, $library_name);
}
$this->versioned_files = $versioned_files;
$this->csp_nonce = preg_replace('/[^A-Za-z0-9\+\/=]/', '', base64_encode(random_bytes(18)));
$this->csp_domains = [];
}
/**
* Add a library to the collection.
*
* @param array $data Array with asset data.
* @param string|null $library_name
*
* @return $this
*/
public function addLibrary(array $data, string $library_name = null): self
{
$library_name = $library_name ?? uniqid('', false);
$this->libraries[$library_name] = [
'name' => $library_name,
'order' => $data['order'] ?? 0,
'files' => $data['files'] ?? [],
'inline' => $data['inline'] ?? [],
'require' => $data['require'] ?? [],
'replace' => $data['replace'] ?? [],
];
return $this;
}
/**
* @param string $library_name
*
* @return array|null
*/
public function getLibrary(string $library_name): ?array
{
return $this->libraries[$library_name] ?? null;
}
/**
* Returns the randomly generated nonce for inline CSP for this request.
* @return string
*/
public function getCspNonce(): string
{
return $this->csp_nonce;
}
/**
* Returns the list of approved domains for CSP header inclusion.
* @return array
*/
public function getCspDomains(): array
{
return $this->csp_domains;
}
/**
* Add a single javascript file.
*
* @param string|array $js_script
*
* @return $this
*/
public function addJs($js_script): self
{
$this->load([
'order' => 100,
'files' => [
'js' => [
(is_array($js_script)) ? $js_script : ['src' => $js_script],
],
],
]);
return $this;
}
/**
* Loads assets from given name or array definition.
*
* @param mixed $data Name or array definition of library/asset.
*
* @return self
*/
public function load($data): self
{
if (is_array($data)) {
$item = [
'name' => $data['name'] ?? uniqid('', false),
'order' => $data['order'] ?? 0,
'files' => $data['files'] ?? [],
'inline' => $data['inline'] ?? [],
'require' => $data['require'] ?? [],
'replace' => $data['replace'] ?? [],
];
} elseif (isset($this->libraries[$data])) {
$item = $this->libraries[$data];
} else {
throw new InvalidArgumentException(sprintf('Library %s not found!', $data));
}
$name = $item['name'];
// Check if a library is "replaced" by other libraries already loaded.
$is_replaced = false;
foreach ($this->loaded as $loaded_name => $loaded_item) {
if (!empty($loaded_item['replace']) && in_array($name, (array)$loaded_item['replace'], true)) {
$is_replaced = true;
break;
}
}
if (!$is_replaced && !isset($this->loaded[$name])) {
if (!empty($item['replace'])) {
foreach ((array)$item['replace'] as $replace_name) {
$this->unload($replace_name);
}
}
if (!empty($item['require'])) {
foreach ((array)$item['require'] as $require_name) {
$this->load($require_name);
}
}
$this->loaded[$name] = $item;
$this->is_sorted = false;
}
return $this;
}
/**
* Unload a given library if it's already loaded.
*
* @param string $name
*
* @return self
*/
public function unload(string $name): self
{
if (isset($this->loaded[$name])) {
unset($this->loaded[$name]);
$this->is_sorted = false;
}
return $this;
}
/**
* Add a single javascript inline script.
*
* @param string|array $js_script
*
* @return $this
*/
public function addInlineJs($js_script, $order = 100): self
{
$this->load([
'order' => $order,
'inline' => [
'js' => (is_array($js_script)) ? $js_script : [$js_script],
],
]);
return $this;
}
/**
* Add a single CSS file.
*
* @param string|array $css_script
*
* @return $this
*/
public function addCss($css_script, $order = 100): self
{
$this->load([
'order' => $order,
'files' => [
'css' => [
(is_array($css_script)) ? $css_script : ['src' => $css_script],
],
],
]);
return $this;
}
/**
* Add a single inline CSS file[s].
*
* @param string|array $css_script
*
* @return $this
*/
public function addInlineCss($css_script): self
{
$this->load([
'order' => 100,
'inline' => [
'css' => (is_array($css_script)) ? $css_script : [$css_script],
],
]);
return $this;
}
/**
* Returns all CSS includes and inline styles.
* @return string HTML tags as string.
*/
public function css()
{
$this->_sort();
$result = [];
foreach ($this->loaded as $item) {
if (!empty($item['files']['css'])) {
foreach ($item['files']['css'] as $file) {
$compiled_attributes = $this->compileAttributes($file, [
'rel' => 'stylesheet',
'type' => 'text/css',
]);
$result[] = '<link ' . implode(' ', $compiled_attributes) . ' />';
}
}
if (!empty($item['inline']['css'])) {
foreach ($item['inline']['css'] as $inline) {
if (!empty($inline)) {
$result[] = '<style type="text/css" nonce="' . $this->csp_nonce . '">' . "\n" . $inline . '</style>';
}
}
}
}
return implode("\n", $result) . "\n";
}
/**
* Returns all script include tags.
* @return string HTML tags as string.
*/
public function js()
{
$this->_sort();
$result = [];
foreach ($this->loaded as $item) {
if (!empty($item['files']['js'])) {
foreach ($item['files']['js'] as $file) {
$compiled_attributes = $this->compileAttributes($file, [
'type' => 'text/javascript',
]);
$result[] = '<script ' . implode(' ', $compiled_attributes) . '></script>';
}
}
}
return implode("\n", $result) . "\n";
}
/**
* Return any inline JavaScript.
*
* @param ServerRequestInterface $request
*
* @return string
*/
public function inlineJs(ServerRequestInterface $request): string
{
$this->_sort();
$result = [];
foreach ($this->loaded as $item) {
if (!empty($item['inline']['js'])) {
foreach ($item['inline']['js'] as $inline) {
if (is_callable($inline)) {
$inline = $inline($request);
}
if (!empty($inline)) {
$result[] = '<script type="text/javascript" nonce="' . $this->csp_nonce . '">' . "\n" . $inline . '</script>';
}
}
}
}
return implode("\n", $result) . "\n";
}
/**
* Sort the list of loaded libraries.
*/
protected function _sort()
{
if (!$this->is_sorted) {
uasort($this->loaded, function ($a, $b) {
return $a['order'] <=> $b['order']; // SPACESHIP!
});
$this->is_sorted = true;
}
}
/**
* Build the proper include tag for a JS/CSS include.
*
* @param array $file
* @param array $defaults
*
* @return array
*/
protected function compileAttributes(array $file, array $defaults = []): array
{
if (isset($file['src'])) {
$defaults['src'] = $this->getUrl($file['src']);
unset($file['src']);
}
if (isset($file['href'])) {
$defaults['href'] = $this->getUrl($file['href']);
unset($file['href']);
}
if (isset($file['integrity'])) {
$defaults['crossorigin'] = 'anonymous';
}
$attributes = array_merge($defaults, $file);
$compiled_attributes = [];
foreach ($attributes as $attr_key => $attr_val) {
// Check for attributes like "defer"
if ($attr_val === true) {
$compiled_attributes[] = $attr_key;
} else {
$compiled_attributes[] = $attr_key . '="' . $attr_val . '"';
}
}
return $compiled_attributes;
}
/**
* Resolve the URI of the resource, whether local or remote/CDN-based.
*
* @param string $resource_uri
*
* @return string The resolved resource URL.
*/
public function getUrl($resource_uri): string
{
if (isset($this->versioned_files[$resource_uri])) {
$resource_uri = $this->versioned_files[$resource_uri];
}
if (preg_match('/^(https?:)?\/\//', $resource_uri)) {
$this->addDomainToCsp($resource_uri);
return $resource_uri;
}
return '/static/' . $resource_uri;
}
/**
* Add the loaded domain to the full list of CSP-approved domains.
*
* @param string $src
*/
protected function addDomainToCsp($src): void
{
$src_parts = parse_url($src);
$domain = $src_parts['scheme'] . '://' . $src_parts['host'];
if (!isset($this->csp_domains[$domain])) {
$this->csp_domains[$domain] = $domain;
}
}
}

View File

@ -4,7 +4,7 @@ namespace App;
use App\Entity\Repository\UserRepository;
use App\Entity\User;
use App\Exception\NotLoggedInException;
use Azura\Exception;
use App\Exception;
use Mezzio\Session\SessionInterface;
class Auth

169
src/Collection.php Normal file
View File

@ -0,0 +1,169 @@
<?php
/**
* Lightweight "Collection" class.
* Originates from the Slim PHP framework, version 3.
* Slim Framework (https://slimframework.com)
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace App;
use ArrayAccess;
use ArrayIterator;
use IteratorAggregate;
/**
* Collection
* This class provides a common interface used by many other
* classes in a Slim application that manage "collections"
* of data that must be inspected and/or manipulated
*/
class Collection implements ArrayAccess, IteratorAggregate
{
/**
* The source data
* @var array
*/
protected $data = [];
/**
* @param array $items Pre-populate collection with this key-value array
*/
public function __construct(array $items = [])
{
$this->replace($items);
}
/**
* @param array $items
*/
public function replace(array $items): void
{
foreach ($items as $key => $value) {
$this->set($key, $value);
}
}
/**
* @param string $key
* @param mixed $value
*/
public function set($key, $value): void
{
$this->data[$key] = $value;
}
/**
* @return array
*/
public function all(): array
{
return $this->data;
}
/**
* Get collection keys
* @return array The collection's source data keys
*/
public function keys(): array
{
return array_keys($this->data);
}
public function clear(): void
{
$this->data = [];
}
/**
* Does this collection have a given key?
*
* @param string $key The data key
*
* @return bool
*/
public function offsetExists($key): bool
{
return $this->has($key);
}
/**
* @param string $key
*
* @return bool
*/
public function has($key): bool
{
return array_key_exists($key, $this->data);
}
/**
* Get collection item for key
*
* @param string $key The data key
*
* @return mixed The key's value, or the default value
*/
public function offsetGet($key)
{
return $this->get($key);
}
/**
* @param string $key
* @param mixed|null $default
*
* @return mixed|null
*/
public function get($key, $default = null)
{
return $this->has($key) ? $this->data[$key] : $default;
}
/**
* Set collection item
*
* @param string $key The data key
* @param mixed $value The data value
*/
public function offsetSet($key, $value): void
{
$this->set($key, $value);
}
/**
* Remove item from collection
*
* @param string $key The data key
*/
public function offsetUnset($key): void
{
$this->remove($key);
}
/**
* @param string $key
*/
public function remove($key): void
{
unset($this->data[$key]);
}
/**
* Get number of items in collection
* @return int
*/
public function count(): int
{
return count($this->data);
}
/**
* Get collection iterator
* @return ArrayIterator
*/
public function getIterator(): ArrayIterator
{
return new ArrayIterator($this->data);
}
}

63
src/Config.php Normal file
View File

@ -0,0 +1,63 @@
<?php
namespace App;
use const EXTR_OVERWRITE;
class Config
{
protected $_base_folder;
public function __construct($base_folder)
{
if (!is_dir($base_folder)) {
throw new Exception("Invalid base folder for configurations.");
}
$this->_base_folder = $base_folder;
}
/**
* @param string $name
* @param array $inject_vars Variables to pass into the scope of the configuration.
*
* @return array
*/
public function get($name, $inject_vars = []): array
{
$path = $this->_getPath($name);
if (file_exists($path)) {
unset($name);
extract($inject_vars, EXTR_OVERWRITE);
unset($inject_vars);
return require $path;
}
return [];
}
/**
* Return the configuration path resolved by the specified name.
*
* @param string $name
*
* @return string
*/
public function _getPath($name)
{
return $this->_base_folder . DIRECTORY_SEPARATOR . str_replace(['.', '..'], ['', ''], $name) . '.php';
}
/**
* Indicate whether a given configuration file name exists.
*
* @param string $name
*
* @return bool
*/
public function has($name): bool
{
return file_exists($this->_getPath($name));
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace App\Console;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\StreamOutput;
class Application extends \Silly\Edition\PhpDi\Application
{
/**
* Run a one-off command from elsewhere in the application, and pass through the results.
*
* @param string $command
* @param array $args
*
* @return array [$return_code, $return_output]
*/
public function runCommandWithArgs($command, array $args = []): array
{
$input = new ArrayInput(array_merge(['command' => $command], $args));
$input->setInteractive(false);
$temp_stream = fopen('php://temp', 'w+');
$output = new StreamOutput($temp_stream);
$command = $this->find($command);
$result_code = $command->run($input, $output);
rewind($temp_stream);
$result_output = stream_get_contents($temp_stream);
fclose($temp_stream);
return [
$result_code,
$result_output,
];
}
}

View File

@ -4,7 +4,7 @@ namespace App\Console\Command;
use App\Entity;
use App\Sync\Task\Backup;
use App\Utilities;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use InfluxDB\Database;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -0,0 +1,17 @@
<?php
namespace App\Console\Command;
use Redis;
use Symfony\Component\Console\Style\SymfonyStyle;
class ClearCacheCommand extends CommandAbstract
{
public function __invoke(SymfonyStyle $io, Redis $redis)
{
// Flush all Redis entries.
$redis->flushAll();
$io->writeln('Local cache flushed.');
return 0;
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace App\Console\Command;
use App\Console\Application;
use Exception;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\OutputInterface;
abstract class CommandAbstract
{
/** @var Application */
protected $application;
/**
* @param Application $application
*/
public function __construct(Application $application)
{
$this->application = $application;
}
/**
* @return Application
*/
public function getApplication(): Application
{
return $this->application;
}
/**
* @param OutputInterface $output
* @param string $command_name
* @param array $command_args
*
* @throws Exception
*/
protected function runCommand(OutputInterface $output, $command_name, $command_args = [])
{
$command = $this->getApplication()->find($command_name);
$input = new ArrayInput(['command' => $command_name] + $command_args);
$input->setInteractive(false);
$command->run($input, $output);
}
}

View File

@ -3,7 +3,7 @@ namespace App\Console\Command;
use App\Settings;
use App\Version;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Symfony\Component\Console\Style\SymfonyStyle;
use function OpenApi\scan;

View File

@ -4,7 +4,7 @@ namespace App\Console\Command\Internal;
use App\Entity;
use App\Radio\Adapters;
use App\Radio\Backend\Liquidsoap;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -4,7 +4,7 @@ namespace App\Console\Command\Internal;
use App\Entity;
use App\Radio\Adapters;
use App\Radio\Backend\Liquidsoap;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -4,7 +4,7 @@ namespace App\Console\Command\Internal;
use App\Entity;
use App\Radio\Adapters;
use App\Radio\Backend\Liquidsoap;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -3,7 +3,7 @@ namespace App\Console\Command\Internal;
use App\Entity;
use App\Sync\Task\NowPlaying;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Exception;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -3,7 +3,7 @@ namespace App\Console\Command\Internal;
use App\Entity;
use App\Service\AzuraCastCentral;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Symfony\Component\Console\Style\SymfonyStyle;
class GetIpCommand extends CommandAbstract

View File

@ -3,7 +3,7 @@ namespace App\Console\Command\Internal;
use App\Entity;
use App\Radio\AutoDJ;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -2,7 +2,7 @@
namespace App\Console\Command\Internal;
use App\Entity\SftpUser;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Brick\Math\BigInteger;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -5,7 +5,7 @@ use App\Entity;
use App\Message;
use App\MessageQueue;
use App\Radio\Filesystem;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -3,7 +3,7 @@ namespace App\Console\Command;
use App\Entity;
use App\Utilities;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Symfony\Component\Console\Style\SymfonyStyle;
class ListSettingsCommand extends CommandAbstract

View File

@ -2,7 +2,7 @@
namespace App\Console\Command;
use App\Settings;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Gettext\Translations;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;

View File

@ -2,7 +2,7 @@
namespace App\Console\Command;
use App\Settings;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Gettext\Translations;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -2,7 +2,7 @@
namespace App\Console\Command;
use App\Settings;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Symfony\Component\Console\Style\SymfonyStyle;
class MigrateConfigCommand extends CommandAbstract

View File

@ -2,7 +2,7 @@
namespace App\Console\Command;
use App\MessageQueue;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Psr\Log\LoggerInterface;
use const PHP_INT_MAX;

View File

@ -4,7 +4,7 @@ namespace App\Console\Command;
use App\Entity;
use App\Entity\Repository\StationRepository;
use App\Entity\Station;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Exception;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -3,7 +3,7 @@ namespace App\Console\Command;
use App\Entity;
use App\Utilities;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -4,7 +4,7 @@ namespace App\Console\Command;
use App\Entity\Repository\StationRepository;
use App\Entity\Station;
use App\Radio\Configuration;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -3,7 +3,7 @@ namespace App\Console\Command;
use App\Sync\Task\Backup;
use App\Utilities;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use InfluxDB\Database;
use Symfony\Component\Console\Output\OutputInterface;

View File

@ -3,7 +3,7 @@ namespace App\Console\Command;
use App\Acl;
use App\Entity;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -2,7 +2,7 @@
namespace App\Console\Command;
use App\Entity;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Symfony\Component\Console\Style\SymfonyStyle;
class SetSettingCommand extends CommandAbstract

View File

@ -4,7 +4,7 @@ namespace App\Console\Command;
use App\Entity;
use App\Service\AzuraCastCentral;
use App\Settings;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Psr\Container\ContainerInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -3,7 +3,7 @@ namespace App\Console\Command;
use App\Entity\Station;
use App\Settings;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Cake\Chronos\Chronos;
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Loader;

View File

@ -2,7 +2,7 @@
namespace App\Console\Command;
use App\Settings;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use InfluxDB\Database;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -3,7 +3,7 @@ namespace App\Console\Command;
use App;
use App\Sync\Runner;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
class SyncCommand extends CommandAbstract
{

View File

@ -2,7 +2,7 @@
namespace App\Console\Command;
use App;
use Azura\Console\Command\CommandAbstract;
use App\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Exception;
use InvalidArgumentException;

View File

@ -4,7 +4,7 @@ namespace App\Controller\Admin;
use App\Form\ApiKeyForm;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class ApiController extends AbstractAdminCrudController

View File

@ -9,8 +9,8 @@ use App\Form\Form;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Sync\Task\Backup;
use Azura\Config;
use Azura\Session\Flash;
use App\Config;
use App\Session\Flash;
use Exception;
use League\Flysystem\Adapter\Local;
use League\Flysystem\Filesystem;

View File

@ -4,7 +4,7 @@ namespace App\Controller\Admin;
use App\Form\BrandingSettingsForm;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class BrandingController

View File

@ -5,7 +5,7 @@ use App\Entity;
use App\Form\CustomFieldForm;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class CustomFieldsController extends AbstractAdminCrudController

View File

@ -7,7 +7,7 @@ use App\Form\GeoLiteSettingsForm;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Service\IpGeolocator\GeoLite;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class InstallGeoLiteController

View File

@ -6,7 +6,7 @@ use App\Http\Response;
use App\Http\ServerRequest;
use App\Radio\Frontend\SHOUTcast;
use App\Settings;
use Azura\Config;
use App\Config;
use Exception;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UploadedFileInterface;

View File

@ -6,7 +6,7 @@ use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Settings;
use Azura\Exception;
use App\Exception;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;

View File

@ -5,7 +5,7 @@ use App\Acl;
use App\Form\PermissionsForm;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class PermissionsController extends AbstractAdminCrudController

View File

@ -4,7 +4,7 @@ namespace App\Controller\Admin;
use App\Form\SettingsForm;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class SettingsController

View File

@ -7,7 +7,7 @@ use App\Exception\NotFoundException;
use App\Form;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class StationsController extends AbstractAdminCrudController

View File

@ -7,7 +7,7 @@ use App\Exception\NotFoundException;
use App\Form\UserForm;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Psr\Http\Message\ResponseInterface;

View File

@ -2,7 +2,7 @@
namespace App\Controller\Api;
use App\Exception\ValidationException;
use Azura\Http\RouterInterface;
use App\Http\RouterInterface;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;

View File

@ -6,8 +6,8 @@ use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Utilities;
use Azura\Doctrine\Paginator;
use Azura\Exception;
use App\Doctrine\Paginator;
use App\Exception;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\TransactionRequiredException;

View File

@ -4,7 +4,7 @@ namespace App\Controller\Api\Admin;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Doctrine\Paginator;
use App\Doctrine\Paginator;
use Cake\Chronos\Chronos;
use DateTimeZone;
use Doctrine\ORM\EntityManager;

View File

@ -3,7 +3,7 @@ namespace App\Controller\Api\Admin;
use App\Entity;
use App\Exception\ValidationException;
use Azura\Normalizer\DoctrineEntityNormalizer;
use App\Normalizer\DoctrineEntityNormalizer;
use Doctrine\ORM\EntityManager;
use InvalidArgumentException;
use OpenApi\Annotations as OA;

View File

@ -4,7 +4,7 @@ namespace App\Controller\Api;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Timezone;
use App\Timezone;
use Psr\Http\Message\ResponseInterface;
class IndexController

View File

@ -5,7 +5,7 @@ use App\Entity;
use App\Event\Radio\LoadNowPlaying;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\EventDispatcher;
use App\EventDispatcher;
use Doctrine\ORM\EntityManager;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;

View File

@ -6,8 +6,8 @@ use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Utilities;
use Azura\Doctrine\Paginator;
use Azura\Exception;
use App\Doctrine\Paginator;
use App\Exception;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;

View File

@ -231,7 +231,7 @@ class BatchAction
if ('' !== $directory_path) {
$directory_path_meta = $fs->getMetadata($directory_path_full);
if ('dir' !== $directory_path_meta['type']) {
throw new \Azura\Exception(__('Path "%s" is not a folder.', $directory_path_full));
throw new \App\Exception(__('Path "%s" is not a folder.', $directory_path_full));
}
}
@ -246,7 +246,7 @@ class BatchAction
$media->setPath($newPath);
if (!$fs->rename($old_full_path, $media->getPath())) {
throw new \Azura\Exception(__('Could not move "%s" to "%s"', $old_full_path,
throw new \App\Exception(__('Could not move "%s" to "%s"', $old_full_path,
$media->getPath()));
}

View File

@ -5,8 +5,8 @@ use App;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Doctrine\Paginator;
use Azura\Utilities\Csv;
use App\Doctrine\Paginator;
use App\Utilities\Csv;
use Cake\Chronos\Chronos;
use DateTimeZone;
use Doctrine\ORM\EntityManager;

View File

@ -6,7 +6,7 @@ use App\Exception\NotFoundException;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Radio\Adapters;
use Azura\Exception;
use App\Exception;
use Doctrine\ORM\EntityManager;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;

View File

@ -5,7 +5,7 @@ use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Service\IpGeolocation;
use Azura\Utilities\Csv;
use App\Utilities\Csv;
use Cake\Chronos\Chronos;
use DateTimeZone;
use Doctrine\ORM\EntityManager;

View File

@ -5,9 +5,9 @@ use App\Entity;
use App\Exception\NotFoundException;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Doctrine\Paginator;
use Azura\Exception;
use Azura\Http\RouterInterface;
use App\Doctrine\Paginator;
use App\Exception;
use App\Http\RouterInterface;
use Cake\Chronos\Chronos;
use DateTimeZone;
use Doctrine\ORM\EntityManager;

View File

@ -5,8 +5,8 @@ use App;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Doctrine\Paginator;
use Azura\Http\RouterInterface;
use App\Doctrine\Paginator;
use App\Http\RouterInterface;
use Doctrine\ORM\EntityManager;
use InvalidArgumentException;
use OpenApi\Annotations as OA;

View File

@ -6,8 +6,8 @@ use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Utilities;
use Azura\Doctrine\Paginator;
use Azura\Exception;
use App\Doctrine\Paginator;
use App\Exception;
use Doctrine\ORM\EntityManager;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;

View File

@ -7,7 +7,7 @@ use App\Http\Response;
use App\Http\ServerRequest;
use App\Radio\Filesystem;
use App\Utilities;
use Azura\Doctrine\Paginator;
use App\Doctrine\Paginator;
use Psr\Http\Message\ResponseInterface;
class BroadcastsController extends AbstractApiCrudController

View File

@ -4,7 +4,7 @@ namespace App\Controller\Api\Stations;
use App\Entity;
use App\Exception\StationUnsupportedException;
use App\Http\ServerRequest;
use Azura\Http\RouterInterface;
use App\Http\RouterInterface;
use OpenApi\Annotations as OA;
class StreamersController extends AbstractStationApiCrudController

View File

@ -8,9 +8,9 @@ use App\Entity\Settings;
use App\Entity\User;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Exception\RateLimitExceededException;
use Azura\RateLimit;
use Azura\Session\Flash;
use App\Exception\RateLimitExceededException;
use App\RateLimit;
use App\Session\Flash;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;

View File

@ -4,7 +4,7 @@ namespace App\Controller\Frontend\Account;
use App\Auth;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class TwoFactorAction

View File

@ -6,7 +6,7 @@ use App\Exception\NotFoundException;
use App\Form\Form;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Config;
use App\Config;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;

View File

@ -8,7 +8,7 @@ use App\Http\Response;
use App\Http\Router;
use App\Http\ServerRequest;
use App\Radio\Adapters;
use Azura\EventDispatcher;
use App\EventDispatcher;
use Doctrine\ORM\EntityManager;
use InfluxDB\Database;
use Psr\Http\Message\ResponseInterface;

View File

@ -3,7 +3,7 @@ namespace App\Controller\Frontend\Profile;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;

View File

@ -4,7 +4,7 @@ namespace App\Controller\Frontend\Profile;
use App\Form\UserProfileForm;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class EditAction

View File

@ -5,8 +5,8 @@ use App\Auth;
use App\Form\Form;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Config;
use Azura\Session\Flash;
use App\Config;
use App\Session\Flash;
use AzuraForms\Field\AbstractField;
use BaconQrCode;
use Doctrine\ORM\EntityManager;

View File

@ -10,7 +10,7 @@ use App\Form\StationForm;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Settings;
use Azura\Session\Flash;
use App\Session\Flash;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;

View File

@ -5,8 +5,8 @@ use App\Entity\Station;
use App\Exception\NotFoundException;
use App\Form\EntityForm;
use App\Http\ServerRequest;
use Azura\Exception;
use Azura\Exception\CsrfValidationException;
use App\Exception;
use App\Exception\CsrfValidationException;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\OptimisticLockException;

View File

@ -6,8 +6,8 @@ use App\Http\Response;
use App\Http\ServerRequest;
use App\Settings;
use App\Sync\Task\RadioAutomation;
use Azura\Config;
use Azura\Session\Flash;
use App\Config;
use App\Session\Flash;
use Doctrine\ORM\EntityManager;
use Exception;
use Psr\Http\Message\ResponseInterface;

View File

@ -4,7 +4,7 @@ namespace App\Controller\Stations;
use App\Controller\Traits\LogViewerTrait;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Exception;
use App\Exception;
use Psr\Http\Message\ResponseInterface;
class LogsController

View File

@ -5,7 +5,7 @@ use App\Exception\StationUnsupportedException;
use App\Form\StationMountForm;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class MountsController extends AbstractStationCrudController

View File

@ -3,7 +3,7 @@ namespace App\Controller\Stations;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Exception;
use App\Exception;
use Psr\Http\Message\ResponseInterface;
class PlaylistsController

View File

@ -7,7 +7,7 @@ use App\Exception\PermissionDeniedException;
use App\Form\StationRemoteForm;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class RemotesController extends AbstractStationCrudController

View File

@ -5,7 +5,7 @@ use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Radio\Filesystem;
use Azura\Session\Flash;
use App\Session\Flash;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;

View File

@ -5,7 +5,7 @@ namespace App\Controller\Stations\Reports;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Sync\Task\RadioAutomation;
use Azura\Utilities\Csv;
use App\Utilities\Csv;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;

View File

@ -4,7 +4,7 @@ namespace App\Controller\Stations\Reports;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Session\Flash;
use App\Session\Flash;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;

View File

@ -5,7 +5,7 @@ use App\Entity;
use App\Form\Form;
use App\Http\Response;
use App\Http\ServerRequest;
use Azura\Config;
use App\Config;
use Doctrine\ORM\EntityManager;
use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;

View File

@ -7,7 +7,7 @@ use App\Http\Response;
use App\Http\ServerRequest;
use App\Service\AzuraCastCentral;
use App\Service\SftpGo;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class SftpUsersController extends AbstractStationCrudController

View File

@ -7,7 +7,7 @@ use App\Form\StationStreamerForm;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Service\AzuraCastCentral;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class StreamersController extends AbstractStationCrudController

View File

@ -6,7 +6,7 @@ use App\Form\StationWebhookForm;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Webhook\Dispatcher;
use Azura\Session\Flash;
use App\Session\Flash;
use Psr\Http\Message\ResponseInterface;
class WebhooksController extends AbstractStationCrudController

47
src/DeferredCallable.php Normal file
View File

@ -0,0 +1,47 @@
<?php
/**
* Deferred Callable
* Used from:
* Slim Framework (https://slimframework.com)
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace App;
use Slim\Interfaces\CallableResolverInterface;
class DeferredCallable
{
/**
* @var callable|string
*/
protected $callable;
/**
* @var CallableResolverInterface|null
*/
protected $callableResolver;
/**
* @param callable|string $callable
* @param CallableResolverInterface|null $resolver
*/
public function __construct($callable, ?CallableResolverInterface $resolver = null)
{
$this->callable = $callable;
$this->callableResolver = $resolver;
}
public function __invoke(...$args)
{
/** @var callable $callable */
$callable = $this->callable;
if ($this->callableResolver) {
$callable = $this->callableResolver->resolve($callable);
}
return $callable(...$args);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Doctrine\Functions;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
* RandFunction ::= "RAND" "(" ")"
*/
class Rand extends FunctionNode
{
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(SqlWalker $sqlWalker)
{
return 'RAND()';
}
}

View File

@ -0,0 +1,67 @@
<?php
/**
* DoctrineExtensions Paginate
* LICENSE
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/
namespace App\Doctrine\Paginate;
use Doctrine\ORM\Query\AST\AggregateExpression;
use Doctrine\ORM\Query\AST\PathExpression;
use Doctrine\ORM\Query\AST\SelectExpression;
use Doctrine\ORM\Query\AST\SelectStatement;
use Doctrine\ORM\Query\TreeWalkerAdapter;
class CountWalker extends TreeWalkerAdapter
{
/**
* Walks down a SelectStatement AST node, modifying it to retrieve a COUNT
*
* @param SelectStatement $AST
*
* @return void
*/
public function walkSelectStatement(SelectStatement $AST)
{
$parent = null;
$parentName = null;
foreach ($this->_getQueryComponents() AS $dqlAlias => $qComp) {
// skip mixed data in query
if (isset($qComp['resultVariable'])) {
continue;
}
if ($qComp['parent'] === null && $qComp['nestingLevel'] == 0) {
$parent = $qComp;
$parentName = $dqlAlias;
break;
}
}
$pathExpression = new PathExpression(
PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $parentName,
$parent['metadata']->getSingleIdentifierFieldName()
);
$pathExpression->type = PathExpression::TYPE_STATE_FIELD;
$AST->selectClause->selectExpressions = [
new SelectExpression(
new AggregateExpression('count', $pathExpression, true), null
),
];
// ORDER BY is not needed, only increases query execution through unnecessary sorting.
$AST->orderByClause = null;
// GROUP BY will break things, we are trying to get a count of all
$AST->groupByClause = null;
}
}

221
src/Doctrine/Paginator.php Normal file
View File

@ -0,0 +1,221 @@
<?php
namespace App\Doctrine;
use App\Http\RequestHelper;
use App\Http\Response;
use App\Http\ResponseHelper;
use App\Http\Router;
use App\Http\ServerRequest;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator;
use InvalidArgumentException;
use Psr\Http\Message\ResponseInterface;
class Paginator
{
/** @var Query */
protected $query;
/** @var Router */
protected $router;
/** @var int */
protected $current_page = 1;
/** @var int */
protected $per_page = 15;
/** @var int */
protected $max_per_page = 50;
/** @var bool Whether the current request is from jQuery Bootgrid */
protected $is_bootgrid = false;
/** @var bool Whether to show pagination controls. */
protected $is_disabled = false;
/** @var callable|null A callable postprocessor that can be run on each result. */
protected $postprocessor;
public function __construct($query)
{
if ($query instanceof QueryBuilder) {
$query = $query->getQuery();
}
if (!($query instanceof Query)) {
throw new InvalidArgumentException('Query specified is not a Doctrine query.');
}
$this->query = $query;
}
public function getQuery(): Query
{
return $this->query;
}
public function getCurrentPage(): int
{
return $this->current_page;
}
public function setCurrentPage(int $current_page): void
{
$this->current_page = ($current_page > 0) ? $current_page : 1;
}
public function setMaxPerPage(int $max_per_page): void
{
$this->max_per_page = ($max_per_page > 0) ? $max_per_page : 1;
$this->is_disabled = false;
}
public function getPerPage(): int
{
return $this->per_page;
}
public function setPerPage(int $per_page): void
{
if ($per_page > 0) {
$this->per_page = ($per_page <= $this->max_per_page) ? $per_page : $this->max_per_page;
} else {
$this->per_page = -1;
}
$this->is_disabled = false;
}
public function getRouter(): Router
{
return $this->router;
}
public function setRouter(Router $router): void
{
$this->router = $router;
}
public function isFromBootgrid(): bool
{
return $this->is_bootgrid;
}
public function setFromRequest(ServerRequest $request): void
{
$params = $request->getQueryParams();
$this->is_disabled = true;
$this->is_bootgrid = isset($params['rowCount']) || isset($params['searchPhrase']);
if ($this->is_bootgrid) {
$this->setCurrentPage((int)$params['current']);
$this->setPerPage((int)$params['rowCount']);
} else {
if (isset($params['page'])) {
$this->setCurrentPage((int)$params['page']);
}
if (isset($params['per_page'])) {
$this->setPerPage((int)$params['per_page']);
}
}
$router = $request->getRouter();
$this->setRouter($router);
}
public function setPostprocessor(callable $postprocessor)
{
$this->postprocessor = $postprocessor;
}
/**
* @return bool
*/
public function isDisabled(): bool
{
return $this->is_disabled;
}
/**
* @param bool $is_disabled
*/
public function setIsDisabled(bool $is_disabled): void
{
$this->is_disabled = $is_disabled;
}
public function write(Response $response): ResponseInterface
{
$paginator = $this->getPaginator();
$total = count($paginator);
$total_pages = ($this->per_page === -1)
? 1
: ceil($total / $this->per_page);
if ($this->postprocessor) {
$results = [];
$postprocessor = $this->postprocessor;
foreach ($paginator as $result) {
$results[] = $postprocessor($result);
}
} else {
$results = iterator_to_array($paginator);
}
if ($this->is_disabled) {
return $response->withJson($results);
}
if ($this->is_bootgrid) {
return $response->withJson([
'current' => $this->current_page,
'rowCount' => $this->per_page,
'total' => $paginator->count(),
'rows' => $results,
]);
}
$page_links = [];
if ($this->router instanceof Router) {
$page_links['first'] = $this->router->fromHereWithQuery(null, [], ['page' => 1]);
$prev_page = ($this->current_page > 1) ? $this->current_page - 1 : 1;
$page_links['previous'] = $this->router->fromHereWithQuery(null, [], ['page' => $prev_page]);
$next_page = ($this->current_page < $total_pages) ? $this->current_page + 1 : $total_pages;
$page_links['next'] = $this->router->fromHereWithQuery(null, [], ['page' => $next_page]);
$page_links['last'] = $this->router->fromHereWithQuery(null, [], ['page' => $total_pages]);
}
return $response->withJson([
'page' => $this->current_page,
'per_page' => $this->per_page,
'total' => $paginator->count(),
'total_pages' => $total_pages,
'links' => $page_links,
'rows' => $results,
]);
}
public function getPaginator()
{
static $paginator;
if (!$paginator) {
if (!$this->is_disabled && $this->per_page !== -1) {
$offset = ($this->current_page - 1) * $this->per_page;
$this->query->setFirstResult($offset);
$this->query->setMaxResults($this->per_page);
}
$paginator = new DoctrinePaginator($this->query);
}
return $paginator;
}
}

Some files were not shown because too many files have changed in this diff Show More