diff --git a/composer.json b/composer.json index dfe31c11aba27c0eb351111ad07abe651d6f7b29..50b3f8a6ec937cd12206e702991703900f633589 100644 --- a/composer.json +++ b/composer.json @@ -9,17 +9,16 @@ "camspiers/json-pretty": "~1.0.2", "monolog/monolog": "~1.21.0", "php-http/curl-client": "~1.7.0", - "woohoolabs/yang": "~0.9.0", + "woohoolabs/yang": "2.3.2", "codeception/codeception": "~4.1.21", "codeception/module-asserts": "^1.3" }, "require": { "php": "^7.2", "guzzlehttp/psr7": "~1.4.2", - "neomerx/json-api": "~1.0.9", - "slim/slim": "~3.12.3", + "neomerx/json-api": "4.0.1", "spomky-labs/otphp": "^8.3.3", - "tuupola/cors-middleware": "~0.5.2", + "tuupola/cors-middleware": "1.2.1", "tecnickcom/tcpdf": "^6.3", "scssphp/scssphp": "^1.4", "symfony/yaml": "^3.4", @@ -43,6 +42,9 @@ "ext-pcre": "*", "ext-pdo": "*", "ext-mbstring": "*", - "opis/json-schema": "^1.0" + "opis/json-schema": "^1.0", + "slim/psr7": "1.4", + "slim/slim": "4.7.1", + "php-di/php-di": "6.3.4" } } diff --git a/composer.lock b/composer.lock index 0532937da51c366b8db4fd5e52a8cd7c28f8a3b1..440bb705a837ef291243ddaeb13a2e385cdf13cf 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "dc13abed7b7557def19c639c0b91cb4f", + "content-hash": "98af1effd6c2da72cc51ac552e851451", "packages": [ { "name": "algo26-matthias/idna-convert", @@ -274,6 +274,62 @@ }, "time": "2020-06-29T00:56:53+00:00" }, + { + "name": "fig/http-message-util", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message-util.git", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "suggest": { + "psr/http-message": "The package containing the PSR-7 interfaces" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Fig\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-message-util/issues", + "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" + }, + "time": "2020-11-24T22:02:12+00:00" + }, { "name": "gossi/docblock", "version": "v1.6", @@ -657,36 +713,37 @@ }, { "name": "neomerx/json-api", - "version": "v1.0.9", + "version": "v4.0.1", "source": { "type": "git", "url": "https://github.com/neomerx/json-api.git", - "reference": "c911b7494496e79f9de72ee40d6a2b791caaf95b" + "reference": "0e45254a4574a3118e0ed663312b43aca23b89c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/neomerx/json-api/zipball/c911b7494496e79f9de72ee40d6a2b791caaf95b", - "reference": "c911b7494496e79f9de72ee40d6a2b791caaf95b", + "url": "https://api.github.com/repos/neomerx/json-api/zipball/0e45254a4574a3118e0ed663312b43aca23b89c7", + "reference": "0e45254a4574a3118e0ed663312b43aca23b89c7", "shasum": "" }, "require": { - "php": ">=5.5.0", - "psr/http-message": "^1.0", - "psr/log": "^1.0" + "php": ">=7.1.0" }, "require-dev": { - "mockery/mockery": "~0.9.4", - "monolog/monolog": "^1.18", + "friendsofphp/php-cs-fixer": "^2.14", + "mockery/mockery": "^1.0", "phpmd/phpmd": "^2.6", - "phpunit/phpunit": "^4.6 || ^5.0 || ^6.0", - "scrutinizer/ocular": "^1.3", - "squizlabs/php_codesniffer": "^2.5" + "phpunit/phpunit": "^7.0", + "scrutinizer/ocular": "^1.4", + "squizlabs/php_codesniffer": "^2.9" }, "type": "library", "autoload": { "psr-4": { "Neomerx\\JsonApi\\": "src/" - } + }, + "files": [ + "src/I18n/format.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -710,9 +767,9 @@ ], "support": { "issues": "https://github.com/neomerx/json-api/issues", - "source": "https://github.com/neomerx/json-api/tree/v1.x" + "source": "https://github.com/neomerx/json-api/tree/develop" }, - "time": "2018-02-21T13:45:30+00:00" + "time": "2020-03-03T05:56:54+00:00" }, { "name": "nikic/fast-route", @@ -764,6 +821,71 @@ }, "time": "2018-02-13T20:26:39+00:00" }, + { + "name": "opis/closure", + "version": "3.6.2", + "source": { + "type": "git", + "url": "https://github.com/opis/closure.git", + "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/closure/zipball/06e2ebd25f2869e54a306dda991f7db58066f7f6", + "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0 || ^8.0" + }, + "require-dev": { + "jeremeamia/superclosure": "^2.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\Closure\\": "src/" + }, + "files": [ + "functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.", + "homepage": "https://opis.io/closure", + "keywords": [ + "anonymous functions", + "closure", + "function", + "serializable", + "serialization", + "serialize" + ], + "support": { + "issues": "https://github.com/opis/closure/issues", + "source": "https://github.com/opis/closure/tree/3.6.2" + }, + "time": "2021-04-09T13:42:10+00:00" + }, { "name": "opis/json-schema", "version": "1.1.0", @@ -1053,6 +1175,171 @@ }, "time": "2018-08-04T14:22:05+00:00" }, + { + "name": "php-di/invoker", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "540c27c86f663e20fe39a24cd72fa76cdb21d41a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/540c27c86f663e20fe39a24cd72fa76cdb21d41a", + "reference": "540c27c86f663e20fe39a24cd72fa76cdb21d41a", + "shasum": "" + }, + "require": { + "psr/container": "~1.0" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "phpunit/phpunit": "~4.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "support": { + "issues": "https://github.com/PHP-DI/Invoker/issues", + "source": "https://github.com/PHP-DI/Invoker/tree/master" + }, + "time": "2017-03-20T19:28:22+00:00" + }, + { + "name": "php-di/php-di", + "version": "6.3.4", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PHP-DI.git", + "reference": "f53bcba06ab31b18e911b77c039377f4ccd1f7a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/f53bcba06ab31b18e911b77c039377f4ccd1f7a5", + "reference": "f53bcba06ab31b18e911b77c039377f4ccd1f7a5", + "shasum": "" + }, + "require": { + "opis/closure": "^3.5.5", + "php": ">=7.2.0", + "php-di/invoker": "^2.0", + "php-di/phpdoc-reader": "^2.0.1", + "psr/container": "^1.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "doctrine/annotations": "~1.2", + "friendsofphp/php-cs-fixer": "^2.4", + "mnapoli/phpunit-easymock": "^1.2", + "ocramius/proxy-manager": "^2.0.2", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^8.5|^9.0" + }, + "suggest": { + "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", + "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" + }, + "type": "library", + "autoload": { + "psr-4": { + "DI\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The dependency injection container for humans", + "homepage": "https://php-di.org/", + "keywords": [ + "PSR-11", + "container", + "container-interop", + "dependency injection", + "di", + "ioc", + "psr11" + ], + "support": { + "issues": "https://github.com/PHP-DI/PHP-DI/issues", + "source": "https://github.com/PHP-DI/PHP-DI/tree/6.3.4" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", + "type": "tidelift" + } + ], + "time": "2021-06-10T08:04:48+00:00" + }, + { + "name": "php-di/phpdoc-reader", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PhpDocReader.git", + "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/66daff34cbd2627740ffec9469ffbac9f8c8185c", + "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "require-dev": { + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^8.5|^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpDocReader\\": "src/PhpDocReader" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)", + "keywords": [ + "phpdoc", + "reflection" + ], + "support": { + "issues": "https://github.com/PHP-DI/PhpDocReader/issues", + "source": "https://github.com/PHP-DI/PhpDocReader/tree/2.2.1" + }, + "time": "2020-10-12T12:39:22+00:00" + }, { "name": "phpseclib/phpseclib", "version": "2.0.31", @@ -1268,35 +1555,31 @@ "time": "2020-03-04T10:26:33+00:00" }, { - "name": "pimple/pimple", - "version": "v3.2.3", + "name": "psr/container", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/silexphp/Pimple.git", - "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32" + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32", - "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", "shasum": "" }, "require": { - "php": ">=5.3.0", - "psr/container": "^1.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "^3.2" + "php": ">=5.3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { - "psr-0": { - "Pimple": "src/" + "psr-4": { + "Psr\\Container\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1305,38 +1588,42 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" } ], - "description": "Pimple, a simple Dependency Injection Container", - "homepage": "http://pimple.sensiolabs.org", + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", "keywords": [ + "PSR-11", "container", - "dependency injection" + "container-interface", + "container-interop", + "psr" ], "support": { - "issues": "https://github.com/silexphp/Pimple/issues", - "source": "https://github.com/silexphp/Pimple/tree/master" + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/master" }, - "time": "2018-01-21T07:42:36+00:00" + "time": "2017-02-14T16:28:37+00:00" }, { - "name": "psr/container", - "version": "1.0.0", + "name": "psr/http-factory", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.0.0", + "psr/http-message": "^1.0" }, "type": "library", "extra": { @@ -1346,7 +1633,7 @@ }, "autoload": { "psr-4": { - "Psr\\Container\\": "src/" + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1359,20 +1646,21 @@ "homepage": "http://www.php-fig.org/" } ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", + "description": "Common interfaces for PSR-7 HTTP message factories", "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" ], "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/master" + "source": "https://github.com/php-fig/http-factory/tree/master" }, - "time": "2017-02-14T16:28:37+00:00" + "time": "2019-04-30T12:38:16+00:00" }, { "name": "psr/http-message", @@ -1427,6 +1715,120 @@ }, "time": "2016-08-06T14:39:51+00:00" }, + { + "name": "psr/http-server-handler", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-handler/issues", + "source": "https://github.com/php-fig/http-server-handler/tree/master" + }, + "time": "2018-10-30T16:46:14+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/master" + }, + "time": "2018-10-30T17:12:04+00:00" + }, { "name": "psr/log", "version": "1.1.3", @@ -1477,6 +1879,50 @@ }, "time": "2020-03-23T09:12:05+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "scssphp/scssphp", "version": "v1.4.0", @@ -1544,36 +1990,133 @@ }, "time": "2020-11-07T20:53:41+00:00" }, + { + "name": "slim/psr7", + "version": "1.4", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim-Psr7.git", + "reference": "0dca983ca32a26f4a91fb11173b7b9eaee29e9d6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/0dca983ca32a26f4a91fb11173b7b9eaee29e9d6", + "reference": "0dca983ca32a26f4a91fb11173b7b9eaee29e9d6", + "shasum": "" + }, + "require": { + "fig/http-message-util": "^1.1.5", + "php": "^7.2 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3", + "symfony/polyfill-php80": "^1.22" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.2", + "ext-json": "*", + "http-interop/http-factory-tests": "^0.9.0", + "php-http/psr7-integration-tests": "dev-master", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^8.5 || ^9.5", + "squizlabs/php_codesniffer": "^3.6", + "weirdan/prophecy-shim": "^1.0 || ^2.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\Psr7\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "http://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + } + ], + "description": "Strict PSR-7 implementation", + "homepage": "https://www.slimframework.com", + "keywords": [ + "http", + "psr-7", + "psr7" + ], + "support": { + "issues": "https://github.com/slimphp/Slim-Psr7/issues", + "source": "https://github.com/slimphp/Slim-Psr7/tree/1.4" + }, + "time": "2021-05-08T18:22:56+00:00" + }, { "name": "slim/slim", - "version": "3.12.3", + "version": "4.7.1", "source": { "type": "git", "url": "https://github.com/slimphp/Slim.git", - "reference": "1c9318a84ffb890900901136d620b4f03a59da38" + "reference": "0905e0775f8c1cfb3bbcfabeb6588dcfd8b82d3f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim/zipball/1c9318a84ffb890900901136d620b4f03a59da38", - "reference": "1c9318a84ffb890900901136d620b4f03a59da38", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/0905e0775f8c1cfb3bbcfabeb6588dcfd8b82d3f", + "reference": "0905e0775f8c1cfb3bbcfabeb6588dcfd8b82d3f", "shasum": "" }, "require": { "ext-json": "*", - "ext-libxml": "*", - "ext-simplexml": "*", - "nikic/fast-route": "^1.0", - "php": ">=5.5.0", - "pimple/pimple": "^3.0", + "nikic/fast-route": "^1.3", + "php": "^7.2 || ^8.0", "psr/container": "^1.0", - "psr/http-message": "^1.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0", + "psr/log": "^1.1" }, "require-dev": { - "phpunit/phpunit": "^4.0", - "squizlabs/php_codesniffer": "^2.5" + "adriansuter/php-autoload-override": "^1.2", + "ext-simplexml": "*", + "guzzlehttp/psr7": "^1.7", + "http-interop/http-factory-guzzle": "^1.0", + "laminas/laminas-diactoros": "^2.4", + "nyholm/psr7": "^1.3", + "nyholm/psr7-server": "^1.0.1", + "phpspec/prophecy": "^1.12", + "phpstan/phpstan": "^0.12.58", + "phpunit/phpunit": "^8.5.13", + "slim/http": "^1.2", + "slim/psr7": "^1.3", + "squizlabs/php_codesniffer": "^3.5", + "weirdan/prophecy-shim": "^1.0 || ^2.0.2" + }, + "suggest": { + "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", + "ext-xml": "Needed to support XML format in BodyParsingMiddleware", + "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim", + "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information." }, "type": "library", "autoload": { @@ -1601,6 +2144,11 @@ "email": "rob@akrabat.com", "homepage": "http://akrabat.com" }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + }, { "name": "Gabriel Manricks", "email": "gmanricks@me.com", @@ -1608,7 +2156,7 @@ } ], "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", - "homepage": "https://slimframework.com", + "homepage": "https://www.slimframework.com", "keywords": [ "api", "framework", @@ -1616,10 +2164,26 @@ "router" ], "support": { + "docs": "https://www.slimframework.com/docs/v4/", + "forum": "https://discourse.slimframework.com/", + "irc": "irc://irc.freenode.net:6667/slimphp", "issues": "https://github.com/slimphp/Slim/issues", - "source": "https://github.com/slimphp/Slim/tree/3.x" + "rss": "https://www.slimframework.com/blog/feed.rss", + "slack": "https://slimphp.slack.com/", + "source": "https://github.com/slimphp/Slim", + "wiki": "https://github.com/slimphp/Slim/wiki" }, - "time": "2019-11-28T17:40:33+00:00" + "funding": [ + { + "url": "https://opencollective.com/slimphp", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slim/slim", + "type": "tidelift" + } + ], + "time": "2020-12-01T19:41:22+00:00" }, { "name": "spomky-labs/otphp", @@ -1773,30 +2337,94 @@ "version": "v1.10.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/master" + }, + "time": "2018-09-21T13:07:52+00:00" + }, + { + "name": "symfony/polyfill-php56", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php56.git", + "reference": "13df84e91cd168f247c2f2ec82cc0fa24901c011" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/13df84e91cd168f247c2f2ec82cc0fa24901c011", + "reference": "13df84e91cd168f247c2f2ec82cc0fa24901c011", "shasum": "" }, "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-mbstring": "For best performance" + "php": ">=5.3.3", + "symfony/polyfill-util": "~1.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" + "Symfony\\Polyfill\\Php56\\": "" }, "files": [ "bootstrap.php" @@ -1816,42 +2444,54 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "mbstring", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/master" + "source": "https://github.com/symfony/polyfill-php56/tree/v1.18.1" }, - "time": "2018-09-21T13:07:52+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" }, { - "name": "symfony/polyfill-php56", - "version": "v1.18.1", + "name": "symfony/polyfill-php80", + "version": "v1.23.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php56.git", - "reference": "13df84e91cd168f247c2f2ec82cc0fa24901c011" + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/13df84e91cd168f247c2f2ec82cc0fa24901c011", - "reference": "13df84e91cd168f247c2f2ec82cc0fa24901c011", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", + "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", "shasum": "" }, "require": { - "php": ">=5.3.3", - "symfony/polyfill-util": "~1.0" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1860,10 +2500,13 @@ }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Php56\\": "" + "Symfony\\Polyfill\\Php80\\": "" }, "files": [ "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1871,6 +2514,10 @@ "MIT" ], "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -1880,7 +2527,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -1889,7 +2536,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php56/tree/v1.18.1" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.0" }, "funding": [ { @@ -1905,7 +2552,7 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-util", @@ -2117,28 +2764,97 @@ }, "time": "2020-02-14T14:20:12+00:00" }, + { + "name": "tuupola/callable-handler", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/tuupola/callable-handler.git", + "reference": "0bc7b88630ca753de9aba8f411046856f5ca6f8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tuupola/callable-handler/zipball/0bc7b88630ca753de9aba8f411046856f5ca6f8c", + "reference": "0bc7b88630ca753de9aba8f411046856f5ca6f8c", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0", + "psr/http-server-middleware": "^1.0" + }, + "require-dev": { + "overtrue/phplint": "^1.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "squizlabs/php_codesniffer": "^3.2", + "tuupola/http-factory": "^0.4.0|^1.0", + "zendframework/zend-diactoros": "^1.6.0|^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Tuupola\\Middleware\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mika Tuupola", + "email": "tuupola@appelsiini.net", + "homepage": "https://appelsiini.net/", + "role": "Developer" + } + ], + "description": "Compatibility layer for PSR-7 double pass and PSR-15 middlewares.", + "homepage": "https://github.com/tuupola/callable-handler", + "keywords": [ + "middleware", + "psr-15", + "psr-7" + ], + "support": { + "issues": "https://github.com/tuupola/callable-handler/issues", + "source": "https://github.com/tuupola/callable-handler/tree/1.1.0" + }, + "funding": [ + { + "url": "https://github.com/tuupola", + "type": "github" + } + ], + "time": "2020-09-09T08:31:54+00:00" + }, { "name": "tuupola/cors-middleware", - "version": "0.5.2", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/tuupola/cors-middleware.git", - "reference": "db69d8e67b99570b16e8cd5f78c423ed1167cb21" + "reference": "4f085d11f349e83d18f1eb5802551353b2b093a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tuupola/cors-middleware/zipball/db69d8e67b99570b16e8cd5f78c423ed1167cb21", - "reference": "db69d8e67b99570b16e8cd5f78c423ed1167cb21", + "url": "https://api.github.com/repos/tuupola/cors-middleware/zipball/4f085d11f349e83d18f1eb5802551353b2b093a3", + "reference": "4f085d11f349e83d18f1eb5802551353b2b093a3", "shasum": "" }, "require": { - "neomerx/cors-psr7": "^1.0", - "php": "^5.5 || ^7.0" + "neomerx/cors-psr7": "^1.0.4", + "php": "^7.1|^8.0", + "psr/http-message": "^1.0.1", + "psr/http-server-middleware": "^1.0", + "tuupola/callable-handler": "^1.0", + "tuupola/http-factory": "^1.0.2" }, "require-dev": { - "phpunit/phpunit": "^4.8", - "squizlabs/php_codesniffer": "^2.5", - "zendframework/zend-diactoros": "^1.3" + "equip/dispatch": "^2.0", + "overtrue/phplint": "^1.0", + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "squizlabs/php_codesniffer": "^3.5", + "zendframework/zend-diactoros": "^1.0|^2.0" }, "type": "library", "autoload": { @@ -2154,22 +2870,96 @@ { "name": "Mika Tuupola", "email": "tuupola@appelsiini.net", - "homepage": "http://www.appelsiini.net/", + "homepage": "https://appelsiini.net/", "role": "Developer" } ], - "description": "PSR-7 CORS Middleware", + "description": "PSR-7 and PSR-15 CORS middleware", "homepage": "https://github.com/tuupola/cors-middleware", "keywords": [ "cors", "middleware", - "slim" + "psr-15", + "psr-7" ], "support": { "issues": "https://github.com/tuupola/cors-middleware/issues", - "source": "https://github.com/tuupola/cors-middleware/tree/master" + "source": "https://github.com/tuupola/cors-middleware/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/tuupola", + "type": "github" + } + ], + "time": "2020-10-29T11:01:06+00:00" + }, + { + "name": "tuupola/http-factory", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/tuupola/http-factory.git", + "reference": "aa48841a9f572b9cebe9d3ac5d5d3362a83f57ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tuupola/http-factory/zipball/aa48841a9f572b9cebe9d3ac5d5d3362a83f57ac", + "reference": "aa48841a9f572b9cebe9d3ac5d5d3362a83f57ac", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0", + "psr/http-factory": "^1.0" + }, + "conflict": { + "nyholm/psr7": "<1.0" + }, + "provide": { + "psr/http-factory-implementation": "^1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "^0.7.0", + "overtrue/phplint": "^1.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Tuupola\\Http\\Factory\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mika Tuupola", + "email": "tuupola@appelsiini.net", + "homepage": "https://appelsiini.net/", + "role": "Developer" + } + ], + "description": "Lightweight autodiscovering PSR-17 HTTP factories", + "homepage": "https://github.com/tuupola/http-factory", + "keywords": [ + "http", + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/tuupola/http-factory/issues", + "source": "https://github.com/tuupola/http-factory/tree/1.3.0" }, - "time": "2016-08-12T13:12:58+00:00" + "funding": [ + { + "url": "https://github.com/tuupola", + "type": "github" + } + ], + "time": "2020-10-01T07:46:32+00:00" } ], "packages-dev": [ @@ -5480,89 +6270,6 @@ ], "time": "2021-02-19T12:13:01+00:00" }, - { - "name": "symfony/polyfill-php80", - "version": "v1.23.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", - "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-02-19T12:13:01+00:00" - }, { "name": "symfony/service-contracts", "version": "v2.2.0", @@ -5835,27 +6542,33 @@ }, { "name": "woohoolabs/yang", - "version": "0.9.0", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/woohoolabs/yang.git", - "reference": "00dc9820d48780364cd214537604b032d751a781" + "reference": "da65122971fa6add83751497ec76af1fb6cccf77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/woohoolabs/yang/zipball/00dc9820d48780364cd214537604b032d751a781", - "reference": "00dc9820d48780364cd214537604b032d751a781", + "url": "https://api.github.com/repos/woohoolabs/yang/zipball/da65122971fa6add83751497ec76af1fb6cccf77", + "reference": "da65122971fa6add83751497ec76af1fb6cccf77", "shasum": "" }, "require": { - "php": "^5.6.0||^7.0.0", - "php-http/client-implementation": "^1.0.0", - "php-http/httplug": "^1.0.0" + "php": "^7.2.0||^8.0.0", + "php-http/httplug": "^1.0.0|^2.0.0", + "psr/http-message-implementation": "^1.0.0" }, "require-dev": { - "php-http/guzzle6-adapter": "^1.1.0", - "phpunit/phpunit": "^5.4.0", - "squizlabs/php_codesniffer": "^2.3.1" + "guzzlehttp/psr7": "^1.4.0", + "php-http/guzzle6-adapter": "^2.0.0", + "phpstan/phpstan": "^0.12.0", + "phpstan/phpstan-phpunit": "^0.12.0", + "phpstan/phpstan-strict-rules": "^0.12.0", + "phpunit/phpunit": "^7.0.0||^8.2.0||^9.0.0", + "squizlabs/php_codesniffer": "^3.5.1", + "woohoolabs/coding-standard": "^1.0.0", + "woohoolabs/releaser": "^1.1.0" }, "suggest": { "php-http/guzzle6-adapter": "Allows to use Guzzle 6 as the HTTP client implementation" @@ -5877,18 +6590,18 @@ } ], "description": "Woohoo Labs. Yang", - "homepage": "http://yang.woohoolabs.com", "keywords": [ "Woohoo Labs.", "Yang", "json api", + "psr-18", "psr-7" ], "support": { "issues": "https://github.com/woohoolabs/yang/issues", "source": "https://github.com/woohoolabs/yang" }, - "time": "2016-12-21T20:37:46+00:00" + "time": "2020-11-15T08:55:55+00:00" } ], "aliases": [], @@ -5910,5 +6623,5 @@ "ext-mbstring": "*" }, "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.0.0" } diff --git a/lib/classes/JsonApi/AppFactory.php b/lib/classes/JsonApi/AppFactory.php deleted file mode 100644 index ae715aa936c9968586e87f13ebca6cae7e4176e0..0000000000000000000000000000000000000000 --- a/lib/classes/JsonApi/AppFactory.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php - -namespace JsonApi; - -use Slim\App; -use StudipPlugin; -use JsonApi\Middlewares\RemoveTrailingSlashes; - -/** - * Diese Klasse erstellt eine neue Slim-Applikation und konfiguriert - * diese rudimentär vor. - * - * Dabei werden im `Dependency Container` der Slim-Applikation unter - * dem Schlüssel `plugin` das Stud.IP-Plugin vermerkt und außerdem - * eingestellt, dass Fehler des Slim-Frameworks detailliert angezeigt - * werden sollen, wenn sich Stud.IP im Modus `development` befindet. - * - * Darüber hinaus wird eine Middleware installiert, die alle Requests umleitet, - * die mit einem Schrägstrich enden (und zwar jeweils auf das Pendant - * ohne Schrägstrich). - * - * @see http://www.slimframework.com/ - * @see \Studip\ENV - * @see \JsonApi\Middlewares\RemoveTrailingSlashes - */ -class AppFactory -{ - /** - * Diese Factory-Methode erstellt die Slim-Applikation und - * konfiguriert diese wie oben angegeben. - * - * @return \Slim\App die erstellte Slim-Applikation - */ - public function makeApp() - { - $app = new App(); - $app = $this->configureContainer($app); - $app->add(new RemoveTrailingSlashes()); - - return $app; - } - - // hier wird der Container konfiguriert - private function configureContainer($app) - { - $container = $app->getContainer(); - $container['settings']['displayErrorDetails'] = defined('\\Studip\\ENV') && \Studip\ENV === 'development'; - - $container->register(new Providers\StudipConfig()); - $container->register(new Providers\StudipServices()); - - return $app; - } -} diff --git a/lib/classes/JsonApi/Contracts/JsonApiPlugin.php b/lib/classes/JsonApi/Contracts/JsonApiPlugin.php index f7b607a8fac78c14aabb540f8b49bf525b43ebbf..15f1a6549750452d14fdcb81f09a81b8c4d3a375 100644 --- a/lib/classes/JsonApi/Contracts/JsonApiPlugin.php +++ b/lib/classes/JsonApi/Contracts/JsonApiPlugin.php @@ -28,6 +28,8 @@ interface JsonApiPlugin * * @param \Slim\App $app die Slim-Applikation, in der das Plugin * Routen eintragen möchte + * + * @return void */ public function registerAuthenticatedRoutes(\Slim\App $app); @@ -51,6 +53,8 @@ interface JsonApiPlugin * * @param \Slim\App $app die Slim-Applikation, in der das Plugin * Routen eintragen möchte + * + * @return void */ public function registerUnauthenticatedRoutes(\Slim\App $app); diff --git a/lib/classes/JsonApi/Errors/AuthorizationFailedException.php b/lib/classes/JsonApi/Errors/AuthorizationFailedException.php index 104a4b530056ec5a11f2c02b8d4c1a29011b6608..af3d4fb889c50332c6bc163d9f3ff40bc2fe8d2e 100644 --- a/lib/classes/JsonApi/Errors/AuthorizationFailedException.php +++ b/lib/classes/JsonApi/Errors/AuthorizationFailedException.php @@ -2,7 +2,7 @@ namespace JsonApi\Errors; -use Neomerx\JsonApi\Document\Error; +use Neomerx\JsonApi\Schema\Error; use Neomerx\JsonApi\Exceptions\JsonApiException; /** @@ -15,7 +15,7 @@ class AuthorizationFailedException extends JsonApiException */ public function __construct() { - $error = new Error('Forbidden', null, 403); + $error = new Error(null, null, null, '403', null, 'Forbidden'); parent::__construct($error, 403); } } diff --git a/lib/classes/JsonApi/Errors/BadRequestException.php b/lib/classes/JsonApi/Errors/BadRequestException.php index 577ac22f01ed91e636dea9b8078ac4e2004b98b0..c09a96ad78d19de31e107ed6e76ec1978d0984df 100644 --- a/lib/classes/JsonApi/Errors/BadRequestException.php +++ b/lib/classes/JsonApi/Errors/BadRequestException.php @@ -2,7 +2,7 @@ namespace JsonApi\Errors; -use Neomerx\JsonApi\Document\Error; +use Neomerx\JsonApi\Schema\Error; use Neomerx\JsonApi\Exceptions\JsonApiException; /** @@ -15,7 +15,7 @@ class BadRequestException extends JsonApiException */ public function __construct($detail = null, array $source = null) { - $error = new Error('Bad Request', null, 400, null, null, $detail, $source); + $error = new Error(null, null, null, 400, null, 'Bad Request', $detail, $source); parent::__construct($error, 400); } } diff --git a/lib/classes/JsonApi/Errors/ConflictException.php b/lib/classes/JsonApi/Errors/ConflictException.php index 69b00c5fa1552999a4e1310dcd18fe2c0f9599ca..c5cf0d735607f409f4e59777e3655da7d7789f94 100644 --- a/lib/classes/JsonApi/Errors/ConflictException.php +++ b/lib/classes/JsonApi/Errors/ConflictException.php @@ -2,7 +2,7 @@ namespace JsonApi\Errors; -use Neomerx\JsonApi\Document\Error; +use Neomerx\JsonApi\Schema\Error; use Neomerx\JsonApi\Exceptions\JsonApiException; /** @@ -15,7 +15,7 @@ class ConflictException extends JsonApiException */ public function __construct($error = null) { - $error = new Error($error ?: 'Conflict', null, 409); - parent::__construct($error, 409); + $errorObject = new Error(null, null, null, 409, null, 'Conflict', $error); + parent::__construct($errorObject, 409); } } diff --git a/lib/classes/JsonApi/Errors/ErrorHandler.php b/lib/classes/JsonApi/Errors/ErrorHandler.php new file mode 100644 index 0000000000000000000000000000000000000000..93549b50a169c007021cb554e7ef5749c1ead8e9 --- /dev/null +++ b/lib/classes/JsonApi/Errors/ErrorHandler.php @@ -0,0 +1,140 @@ +<?php + +namespace JsonApi\Errors; + +use Neomerx\JsonApi\Exceptions\JsonApiException; +use Neomerx\JsonApi\Schema\Error; +use Neomerx\JsonApi\Schema\ErrorCollection; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Log\LoggerInterface; +use Slim\App; +use Slim\Exception\HttpException; +use Throwable; + +class ErrorHandler +{ + /** @var \Slim\App */ + private $app; + + public function __construct(App $app) + { + $this->app = $app; + } + + public function __invoke( + ServerRequestInterface $request, + Throwable $exception, + bool $displayErrorDetails, + bool $logErrors, + bool $logErrorDetails, + ?LoggerInterface $logger = null + ): ResponseInterface { + if ($logger) { + $logger->error($exception->getMessage()); + } + + $response = $this->app->getResponseFactory()->createResponse(); + $response->getBody()->write($this->determinePayload($exception, $displayErrorDetails)); + + $code = $this->determineStatusCode($exception, $request->getMethod()); + + return $response->withStatus($code); + } + + protected function determineStatusCode(Throwable $exception, string $method): int + { + if ('OPTIONS' === $method) { + return 200; + } + + if ($exception instanceof HttpException) { + return $exception->getCode(); + } + + if ($exception instanceof JsonApiException) { + return $exception->getHttpCode(); + } + + return 500; + } + + protected function determinePayload(Throwable $exception, bool $displayErrorDetails): string + { + $message = ''; + if ($exception instanceof JsonApiException) { + $httpCode = $exception->getHttpCode(); + $errors = new ErrorCollection(); + foreach ($exception->getErrors() as $error) { + $errors[] = $this->copyError($error, $displayErrorDetails, $exception); + } + } elseif ($exception instanceof HttpException) { + $errors = $this->createErrorCollection( + $exception->getCode(), + $exception->getMessage(), + $exception->getDescription(), + $exception, + $displayErrorDetails + ); + } else { + $errors = $this->createErrorCollection( + '500', + $exception->getMessage(), + null, + $exception, + $displayErrorDetails + ); + } + + if (sizeof($errors)) { + $encoder = $this->app->getContainer()->get('json-api-error-encoder'); + + return $encoder->encodeErrors($errors); + } + + return ''; + } + + private function createErrorCollection( + string $httpCode, + string $message, + ?string $details, + Throwable $exception, + bool $displayErrorDetails + ): ErrorCollection { + /** @var \Exception $exception */ + $errors = new ErrorCollection(); + $errors->add( + new Error( + null, + null, + null, + $httpCode, + null, + $message, + $details, + $displayErrorDetails ? ['backtrace' => explode("\n", $exception->getTraceAsString())] : null + ) + ); + + return $errors; + } + + private function copyError(Error $error, bool $displayErrorDetails, JsonApiException $exception): Error + { + $newError = new Error( + $error->getId(), + $error->getLinks(), + $error->getTypeLinks(), + $error->getStatus(), + $error->getCode(), + $error->getTitle(), + $error->getDetail(), + $displayErrorDetails ? ['backtrace' => explode("\n", $exception->getTraceAsString())] : null, + false, + $error->getMeta() + ); + + return $newError; + } +} diff --git a/lib/classes/JsonApi/Errors/HttpRangeException.php b/lib/classes/JsonApi/Errors/HttpRangeException.php index 950535d2c814ca44d59282084ad572aac394dd57..077d14cda69d0c508b79fa0b96b3bc51d80d215b 100644 --- a/lib/classes/JsonApi/Errors/HttpRangeException.php +++ b/lib/classes/JsonApi/Errors/HttpRangeException.php @@ -2,7 +2,7 @@ namespace JsonApi\Errors; -use Neomerx\JsonApi\Document\Error; +use Neomerx\JsonApi\Schema\Error; use Neomerx\JsonApi\Exceptions\JsonApiException; /** @@ -15,7 +15,7 @@ class HttpRangeException extends JsonApiException */ public function __construct($error = null) { - $error = new Error($error ?: 'Requested Range Not Satisfiable.', null, 416); - parent::__construct($error, 416); + $errorObject = new Error(null, null, null, 416, null, 'Requested Range Not Satisfiable.', $error); + parent::__construct($errorObject, 416); } } diff --git a/lib/classes/JsonApi/Errors/InternalServerError.php b/lib/classes/JsonApi/Errors/InternalServerError.php index 98bae8f1ca9c4182515722a088868eab7fd176d2..ccff364ef4816035593c9480c922b482be637b35 100644 --- a/lib/classes/JsonApi/Errors/InternalServerError.php +++ b/lib/classes/JsonApi/Errors/InternalServerError.php @@ -2,7 +2,7 @@ namespace JsonApi\Errors; -use Neomerx\JsonApi\Document\Error; +use Neomerx\JsonApi\Schema\Error; use Neomerx\JsonApi\Exceptions\JsonApiException; /** @@ -15,7 +15,7 @@ class InternalServerError extends JsonApiException */ public function __construct($detail = null, array $source = null) { - $error = new Error('Internal Server Error', null, 500, null, null, $detail, $source); + $error = new Error(null, null, null, 500, null, 'Internal Server Error', $detail, $source); parent::__construct($error, 500); } } diff --git a/lib/classes/JsonApi/Errors/JsonApiExceptionHandler.php b/lib/classes/JsonApi/Errors/JsonApiExceptionHandler.php deleted file mode 100644 index 25ac09239731e93b24de5843465312882441b294..0000000000000000000000000000000000000000 --- a/lib/classes/JsonApi/Errors/JsonApiExceptionHandler.php +++ /dev/null @@ -1,97 +0,0 @@ -<?php - -namespace JsonApi\Errors; - -use JsonApi\Providers\JsonApiConfig as C; -use Neomerx\JsonApi\Contracts\Factories\FactoryInterface; -use Neomerx\JsonApi\Contracts\Http\Headers\MediaTypeInterface; -use Neomerx\JsonApi\Contracts\Schema\ContainerInterface as SC; -use Neomerx\JsonApi\Document\Error; -use Neomerx\JsonApi\Encoder\EncoderOptions; -use Neomerx\JsonApi\Exceptions\ErrorCollection; -use Neomerx\JsonApi\Exceptions\JsonApiException; -use Psr\Container\ContainerInterface; -use Psr\Http\Message\ResponseInterface as Response; -use Psr\Http\Message\ServerRequestInterface as Request; - -/** - * Dieser spezielle Exception Handler wird in der Slim-Applikation - * für alle JSON-API-Routen installiert und sorgt dafür, dass auch - * evtl. Fehler JSON-API-kompatibel geliefert werden. - */ -class JsonApiExceptionHandler -{ - private $previous; - - private $container; - - /** - * Der Konstruktor... - * - * @param ContainerInterface $container der Dependency Container, - * der in der Slim-Applikation verwendet wird - * @param callable $previous der zuvor installierte `Error - * Handler` als Fallback - */ - public function __construct(ContainerInterface $container, $previous = null) - { - $this->previous = $previous; - $this->container = $container; - } - - /** - * Diese Methode wird aufgerufen, sobald es zu einer Exception - * kam, und generiert eine entsprechende JSON-API-spezifische Response. - * - * @param Request $request der eingehende Request - * @param Response $response die vorbereitete ausgehende Response - * @param \Exception $exception die aufgetretene Exception - * - * @return Response die JSON-API-kompatible Response - */ - public function __invoke(Request $request, Response $response, \Exception $exception) - { - if ($exception instanceof JsonApiException) { - $httpCode = $exception->getHttpCode(); - $errors = $exception->getErrors(); - } else { - $httpCode = 500; - $details = null; - - $debugEnabled = \Studip\ENV === 'development'; - if ($debugEnabled === true) { - $message = $exception->getMessage(); - $details = (string) $exception; - } - $errors = new ErrorCollection(); - $errors->add(new Error(null, null, $httpCode, null, $message, $details)); - } - - if (sizeof($errors)) { - $encoder = $this->createEncoder(); - $response = $response - ->withHeader( - 'Content-Type', - sprintf('%s/%s', - MediaTypeInterface::JSON_API_TYPE, - MediaTypeInterface::JSON_API_SUB_TYPE - ) - ) - ->write($encoder->encodeErrors($errors)); - } - - return $response->withStatus($httpCode); - } - - private function createEncoder() - { - $factory = $this->container[FactoryInterface::class]; - $schemaContainer = $this->container[SC::class]; - - $urlPrefix = $this->container[C::JSON_URL_PREFIX]; - - $encoderOptions = new EncoderOptions(0, $urlPrefix); - - return $factory->createEncoder($schemaContainer, $encoderOptions); - } -} diff --git a/lib/classes/JsonApi/Errors/NotAcceptableException.php b/lib/classes/JsonApi/Errors/NotAcceptableException.php new file mode 100644 index 0000000000000000000000000000000000000000..dddb377da3f6c5867731392325b6a85cb85ab329 --- /dev/null +++ b/lib/classes/JsonApi/Errors/NotAcceptableException.php @@ -0,0 +1,15 @@ +<?php + +namespace JsonApi\Errors; + +use Neomerx\JsonApi\Schema\Error; +use Neomerx\JsonApi\Exceptions\JsonApiException; + +class NotAcceptableException extends JsonApiException +{ + public function __construct() + { + $error = new Error(null, null, null, '406', null, 'Not Acceptable Error'); + parent::__construct($error, 406); + } +} diff --git a/lib/classes/JsonApi/Errors/NotImplementedException.php b/lib/classes/JsonApi/Errors/NotImplementedException.php index 4e8541d683d0ff41364b72e828085d1047775b71..d6f35a1f2a60e9079b2f7c867b33190b35738ab7 100644 --- a/lib/classes/JsonApi/Errors/NotImplementedException.php +++ b/lib/classes/JsonApi/Errors/NotImplementedException.php @@ -2,7 +2,7 @@ namespace JsonApi\Errors; -use Neomerx\JsonApi\Document\Error; +use Neomerx\JsonApi\Schema\Error; use Neomerx\JsonApi\Exceptions\JsonApiException; /** @@ -15,7 +15,7 @@ class NotImplementedException extends JsonApiException */ public function __construct($detail = null, array $source = null) { - $error = new Error('Not Implemented Error', null, 501, null, null, $detail, $source); + $error = new Error(null, null, null, 501, null, 'Not Implemented Error', $detail, $source); parent::__construct($error, 501); } } diff --git a/lib/classes/JsonApi/Errors/RecordNotFoundException.php b/lib/classes/JsonApi/Errors/RecordNotFoundException.php index 9ed0c1a2c8b0c10a325b2efd6e28b99f6dfb9a04..4cf0cb952cba5b3058490c1167e324262381a612 100644 --- a/lib/classes/JsonApi/Errors/RecordNotFoundException.php +++ b/lib/classes/JsonApi/Errors/RecordNotFoundException.php @@ -2,7 +2,7 @@ namespace JsonApi\Errors; -use Neomerx\JsonApi\Document\Error; +use Neomerx\JsonApi\Schema\Error; use Neomerx\JsonApi\Exceptions\JsonApiException; /** @@ -15,7 +15,7 @@ class RecordNotFoundException extends JsonApiException */ public function __construct($error = null) { - $error = new Error($error ?: 'Not Found', null, 404); - parent::__construct($error, 404); + $errorObject = new Error(null, null, null, 404, null, 'Not Found', $error); + parent::__construct($errorObject, 404); } } diff --git a/lib/classes/JsonApi/Errors/UnprocessableEntityException.php b/lib/classes/JsonApi/Errors/UnprocessableEntityException.php index e8a4794a6192aada8c730dff0733f44c104183ec..2af4d896ef457d543a0c5d02cc19bd6ad012ed26 100644 --- a/lib/classes/JsonApi/Errors/UnprocessableEntityException.php +++ b/lib/classes/JsonApi/Errors/UnprocessableEntityException.php @@ -2,7 +2,7 @@ namespace JsonApi\Errors; -use Neomerx\JsonApi\Document\Error; +use Neomerx\JsonApi\Schema\Error; use Neomerx\JsonApi\Exceptions\JsonApiException; /** @@ -15,7 +15,7 @@ class UnprocessableEntityException extends JsonApiException */ public function __construct($detail = null, array $source = null) { - $error = new Error('Unprocesssable Entity', null, 422, null, null, $detail, $source); + $error = new Error(null, null, null, 422, null, 'Unprocesssable Entity', $detail, $source); parent::__construct($error, 422); } } diff --git a/lib/classes/JsonApi/Errors/UnsupportedMediaTypeException.php b/lib/classes/JsonApi/Errors/UnsupportedMediaTypeException.php new file mode 100644 index 0000000000000000000000000000000000000000..ec835717592036df55152443c4964351a0b5b7eb --- /dev/null +++ b/lib/classes/JsonApi/Errors/UnsupportedMediaTypeException.php @@ -0,0 +1,15 @@ +<?php + +namespace JsonApi\Errors; + +use Neomerx\JsonApi\Schema\Error; +use Neomerx\JsonApi\Exceptions\JsonApiException; + +class UnsupportedMediaTypeException extends JsonApiException +{ + public function __construct() + { + $error = new Error(null, null, null, '415', null, 'Unsupported Media Type Error'); + parent::__construct($error, 415); + } +} diff --git a/lib/classes/JsonApi/Errors/UnsupportedRequestError.php b/lib/classes/JsonApi/Errors/UnsupportedRequestError.php index 62ac4fbd2e44ad287ddb6caa2711de40af44d995..3b8bcd54bae6a40950ecf2fd2e0d686ae9fd41c2 100644 --- a/lib/classes/JsonApi/Errors/UnsupportedRequestError.php +++ b/lib/classes/JsonApi/Errors/UnsupportedRequestError.php @@ -2,7 +2,7 @@ namespace JsonApi\Errors; -use Neomerx\JsonApi\Document\Error; +use Neomerx\JsonApi\Schema\Error; use Neomerx\JsonApi\Exceptions\JsonApiException; /** @@ -15,7 +15,7 @@ class UnsupportedRequestError extends JsonApiException */ public function __construct($detail = null, array $source = null) { - $error = new Error('Unsupported request.', null, 403, null, null, $detail, $source); + $error = new Error(null, null, null, 403, null, 'Unsupported request.', $detail, $source); parent::__construct($error, 403); } } diff --git a/lib/classes/JsonApi/JsonApiController.php b/lib/classes/JsonApi/JsonApiController.php index 645d4041dc17d1026630f710cbcd0d60f2df4b19..1718c52f86a1903cfb52f88508d8e5274b243ff5 100644 --- a/lib/classes/JsonApi/JsonApiController.php +++ b/lib/classes/JsonApi/JsonApiController.php @@ -3,10 +3,20 @@ namespace JsonApi; use JsonApi\JsonApiIntegration\JsonApiTrait; +use JsonApi\JsonApiIntegration\QueryParserInterface; +use JsonApi\Middlewares\Authentication; +use Neomerx\JsonApi\Contracts\Encoder\EncoderInterface; +use Neomerx\JsonApi\Contracts\Factories\FactoryInterface; +use Neomerx\JsonApi\Contracts\Http\Headers\HeaderParametersParserInterface; +use Neomerx\JsonApi\Contracts\Http\Headers\MediaTypeInterface; +use Neomerx\JsonApi\Contracts\Http\ResponsesInterface; +use Neomerx\JsonApi\Contracts\Schema\SchemaContainerInterface; +use Neomerx\JsonApi\Contracts\Schema\SchemaInterface; +use Neomerx\JsonApi\Http\Headers\MediaType; +use Neomerx\JsonApi\Schema\Link; use Psr\Container\ContainerInterface; - -use Neomerx\JsonApi\Contracts\Http\Headers\HeadersCheckerInterface; -use Neomerx\JsonApi\Contracts\Http\Headers\HeaderParametersInterface; +use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface as Request; /** * Ein JsonApiController ist die einfachste Möglichkeit, eine eigene @@ -28,19 +38,426 @@ use Neomerx\JsonApi\Contracts\Http\Headers\HeaderParametersInterface; */ class JsonApiController { - use JsonApiTrait; + /** + * @var \Slim\App + */ + protected $app; + + /** + * @var ContainerInterface; + */ + protected $container; + + /** + * @var FactoryInterface + */ + protected $factory; + + /** + * @var EncoderInterface + */ + protected $encoder; + + /** + * @var SchemaContainerInterface + */ + protected $schemaContainer; + + /** + * @var QueryParserInterface + */ + protected $queryParser; /** * Der Konstruktor. + */ + public function __construct( + \Slim\App $app, + ContainerInterface $container, + FactoryInterface $factory, + EncoderInterface $encoder, + SchemaContainerInterface $schemaContainer, + QueryParserInterface $queryParser, + HeaderParametersParserInterface $headerParametersParser + ) { + $this->app = $app; + $this->container = $container; + $this->factory = $factory; + $this->encoder = $encoder; + $this->schemaContainer = $schemaContainer; + $this->queryParser = $queryParser; + + $queryChecker = new JsonApiIntegration\QueryChecker( + $this->allowUnrecognizedParams, + $this->allowedIncludePaths, + $this->allowedFieldSetTypes, + $this->allowedSortFields, + $this->allowedPagingParameters, + $this->allowedFilteringParameters + ); + + $queryChecker->checkQuery($queryParser); + + $this->checkAcceptHeader($headerParametersParser); + $this->checkContentTypeHeader($headerParametersParser); + } + + /** + * If unrecognized parameters should be allowed in input parameters. + * + * @var bool + */ + protected $allowUnrecognizedParams = false; + + /** + * A list of allowed include paths in input parameters. + * + * Empty array [] means clients are not allowed to specify include paths and 'null' means all paths are allowed. + * + * @var string[]|null + */ + protected $allowedIncludePaths = []; + + /** + * A list of JSON API types which clients can sent field sets to. + * + * Possible values + * + * $allowedFieldSetTypes = null; // <-- for all types all fields are allowed + * + * $allowedFieldSetTypes = []; // <-- non of the types and fields are allowed + * + * $allowedFieldSetTypes = [ + * 'people' => null, // <-- all fields for 'people' are allowed + * 'comments' => [], // <-- no fields for 'comments' are allowed (all denied) + * 'posts' => ['title', 'body'], // <-- only 'title' and 'body' fields are allowed for 'posts' + * ]; * - * @param ContainerInterface $container der Dependency Container + * @var string[]|null */ - public function __construct(ContainerInterface $container) + protected $allowedFieldSetTypes = null; + + /** + * A list of allowed sort field names in input parameters. + * + * Empty array [] means clients are not allowed to specify sort fields and 'null' means all fields are allowed. + * + * @var string[]|null + */ + protected $allowedSortFields = []; + + /** + * A list of allowed pagination input parameters (e.g 'number', 'size', 'offset' and etc). + * + * Empty array [] means clients are not allowed to specify paging and 'null' means all parameters are allowed. + * + * @var string[]|null + */ + protected $allowedPagingParameters = []; + + /** + * A list of allowed filtering input parameters. + * + * Empty array [] means clients are not allowed to specify filtering and 'null' means all parameters are allowed. + * + * @var string[]|null + */ + protected $allowedFilteringParameters = []; + + // ***** RESPONSE GENERATORS ***** + + /** + * Get response with HTTP code only. + */ + protected function getCodeResponse(int $statusCode, array $headers = []): Response { - $this->container = $container; - $this->initJsonApiSupport($container); + $responses = $this->getResponses(); + + return $responses->getCodeResponse($statusCode, $headers); + } + + /** + * Get response with meta information only. + * + * @param array|object $meta Meta information + * @param int $statusCode + */ + protected function getMetaResponse($meta, $statusCode = ResponsesInterface::HTTP_OK, array $headers = []): Response + { + $responses = $this->getResponses(); + + return $responses->getMetaResponse($meta, $statusCode, $headers); + } + + /** + * Get response with regular JSON API Document in body. + * + * @param object|array $data + * @param int $statusCode + * @param array|null $links + * @param mixed $meta + */ + protected function getContentResponse( + $data, + $statusCode = ResponsesInterface::HTTP_OK, + $links = [], + $meta = [], + array $headers = [] + ): Response { + $responses = $this->getResponses($links, $meta); + + return $responses->getContentResponse($data, $statusCode, $headers); + } + + /** + * Get response with only resource identifiers. + * + * @param object|array $data + * @param array|null $links + * @param mixed $meta + */ + protected function getIdentifiersResponse($data, $links = [], $meta = [], array $headers = []): Response + { + $responses = $this->getResponses($links, $meta); + $statusCode = ResponsesInterface::HTTP_OK; + + return $responses->getIdentifiersResponse($data, $statusCode, $headers); + } + + /** + * Get response with paginated resource identifiers. + * + * @param object|array $data + * @param ?int $total + * @param array|null $links + * @param mixed $meta + */ + protected function getPaginatedIdentifiersResponse( + $data, + $total, + $links = [], + $meta = [], + array $headers = [] + ): Response { + list($offset, $limit) = $this->getOffsetAndLimit(); + + $meta['page'] = [ + 'offset' => (int) $offset, + 'limit' => (int) $limit, + ]; + + if (isset($total)) { + $meta['page']['total'] = (int) $total; + } + + $paginator = new JsonApiIntegration\Paginator($total, $offset, $limit); + + foreach (words('first last prev next') as $rel) { + if (list($off, $lim) = $paginator->{'get'.ucfirst($rel).'PageOffsetAndLimit'}()) { + $links[$rel] = $this->createLink($off, $lim); + } + } + + $responses = $this->getResponses($links, $meta); + $statusCode = ResponsesInterface::HTTP_OK; + + return $responses->getIdentifiersResponse($data, $statusCode, $headers); + } + + /** + * @param object $resource + * @param array|null $links + * @param mixed $meta + */ + protected function getCreatedResponse($resource, $links = [], $meta = [], array $headers = []): Response + { + $responses = $this->getResponses($links, $meta); + $urlPrefix = $this->container->get('json-api-integration-urlPrefix'); + $url = $this->schemaContainer + ->getSchema($resource) + ->getSelfLink($resource) + ->getStringRepresentation($urlPrefix); + + return $responses->getCreatedResponse($resource, $url, $headers); + } + + /** + * @param object|array $data + * @param ?int $total + * @param int $statusCode + * @param array|null $links + * @param mixed $meta + */ + protected function getPaginatedContentResponse( + $data, + $total, + $statusCode = ResponsesInterface::HTTP_OK, + $links = [], + $meta = [], + array $headers = [] + ): Response { + list($offset, $limit) = $this->getOffsetAndLimit(); + + $meta['page'] = [ + 'offset' => (int) $offset, + 'limit' => (int) $limit, + ]; + + if (isset($total)) { + $meta['page']['total'] = (int) $total; + } + + $paginator = new JsonApiIntegration\Paginator($total, $offset, $limit); + + foreach (words('first last prev next') as $rel) { + if (list($off, $lim) = $paginator->{'get'.ucfirst($rel).'PageOffsetAndLimit'}()) { + $links[$rel] = $this->createLink($off, $lim); + } + } + + $responses = $this->getResponses($links, $meta); + + return $responses->getContentResponse($data, $statusCode, $headers); + } + + protected function getQueryParameters(): QueryParserInterface + { + return $this->queryParser; + } + + /** + * Liefert Offset und Limit aus den Request-Parametern zurück. + * + * @param int $offsetDefault optional; gibt den Standard-Offset + * an, falls dieser Wert nicht im Request gesetzt ist + * @param int $limitDefault optional; gibt das Standard-Limit an, + * falls dieser Wert nicht im Request gesetzt ist + * + * @return array<int> { + * + * @var int $offset der im Request gesetzte Offset oder + * ansonsten der Default-Wert 0 + * @var int $limit das im Request gesetzte Limit oder + * ansonsten der Default-Wert 30 + * } + */ + protected function getOffsetAndLimit($offsetDefault = 0, $limitDefault = 30): array + { + $params = iterator_to_array($this->queryParser->getPagination()); + + return [ + $params && array_key_exists('offset', $params) ? (int) $params['offset'] : $offsetDefault, + $params && array_key_exists('limit', $params) ? (int) $params['limit'] : $limitDefault, + ]; + } + + // Hier wird der aktuelle Link zusätzlich noch mit Paginierung ausgestattet + private function createLink(int $offset, int $limit): Link + { + $request = $this->container->get('request'); + $queryParams = $request->getQueryParams(); + $queryParams['page']['offset'] = $offset; + $queryParams['page']['limit'] = $limit; + + $uri = $request->getUri()->withQuery(http_build_query($queryParams)); + + $path = $uri->getPath(); + $query = $uri->getQuery(); + $fragment = $uri->getFragment(); + + $uriString = $path.($query ? '?'.$query : '').($fragment ? '#'.$fragment : ''); + + return new Link(false, $uriString, false); + } + + /** + * Gibt null oder das User-Objekt des "eingeloggten" Nutzers zurück. + * + * @param Request $request Request der eingehende Request + * + * @return mixed entweder null oder das User-Objekt des + * "eingeloggten" Nutzers + */ + public function getUser(Request $request) + { + return $request->getAttribute(Authentication::USER_KEY, null); + } + + /** + * Gibt das Schema zu einer beliebigen Ressource zurück. + * + * @param mixed $resource die Ressource, zu der das Schema geliefert werden soll + * + * @return SchemaInterface das Schema zur Ressource + */ + protected function getSchema($resource): SchemaInterface + { + return $this->schemaContainer->getSchema($resource); + } + + protected function getResponses(array $links = [], array $meta = []): ResponsesInterface + { + $paths = $this->queryParser->getIncludePaths(); + $fieldSets = iterator_to_array($this->queryParser->getFields()); + + $encoder = $this->encoder + ->withIncludedPaths($paths) + ->withFieldSets($fieldSets) + ->withLinks($links); + if (count($meta)) { + $encoder = $encoder->withMeta($meta); + } + + $mediaType = new MediaType(MediaTypeInterface::JSON_API_TYPE, MediaTypeInterface::JSON_API_SUB_TYPE); + + return new JsonApiIntegration\Responses($encoder, $mediaType); + } + + private function checkAcceptHeader(HeaderParametersParserInterface $headerParametersParser): void + { + $request = $this->container->get('request'); + $accept = $request->getHeader(HeaderParametersParserInterface::HEADER_ACCEPT); + if (count($accept)) { + $mediaType = $this->factory->createMediaType( + MediaTypeInterface::JSON_API_TYPE, + MediaTypeInterface::JSON_API_SUB_TYPE + ); + + foreach ($headerParametersParser->parseAcceptHeader($accept[0]) as $acceptMediaType) { + if ($mediaType->matchesTo($acceptMediaType)) { + return; + } + } + } + throw new Errors\NotAcceptableException(); + } + + private function checkContentTypeHeader(HeaderParametersParserInterface $headerParametersParser): void + { + $request = $this->container->get('request'); + if ($this->doesRequestHaveBody($request)) { + $contentType = $request->getHeader(HeaderParametersParserInterface::HEADER_CONTENT_TYPE); + if (count($contentType)) { + $mediaType = $this->factory->createMediaType( + MediaTypeInterface::JSON_API_TYPE, + MediaTypeInterface::JSON_API_SUB_TYPE + ); + $parsedContentType = $headerParametersParser->parseContentTypeHeader($contentType[0]); + if ($mediaType->matchesTo($parsedContentType)) { + return; + } + } + throw new Errors\UnsupportedMediaTypeException(); + } + } + + private function doesRequestHaveBody(Request $request): bool + { + if (count($request->getHeader('Transfer-Encoding'))) { + return true; + } + $contentLength = $request->getHeader('Content-Length'); - $headerChecker = $this->container[HeadersCheckerInterface::class]; - $headerChecker->checkHeaders($this->container[HeaderParametersInterface::class]); + return count($contentLength) && $contentLength[0] > 0; } } diff --git a/lib/classes/JsonApi/JsonApiIntegration/Container.php b/lib/classes/JsonApi/JsonApiIntegration/Container.php deleted file mode 100644 index 7f9911ac7e4ed1fc7f380d4d4e240467f7127c85..0000000000000000000000000000000000000000 --- a/lib/classes/JsonApi/JsonApiIntegration/Container.php +++ /dev/null @@ -1,98 +0,0 @@ -<?php - -namespace JsonApi\JsonApiIntegration; - -class Container extends \Neomerx\JsonApi\Schema\Container -{ - /** - * Überprüft nicht nur, ob es ein mapping zum $type gibt, sondern - * sucht sonst auch nach mappings der Oberklassen bzw. Interfaces. - * - * @param string $type - * - * @return bool - */ - protected function hasProviderMapping($type) - { - if (parent::hasProviderMapping($type)) { - return true; - } - - foreach ($this->getParentClassesAndInterfaces($type) as $class) { - if (parent::hasProviderMapping($class)) { - return true; - } - } - - return false; - } - - /** - * Liefert nicht nur direkte Treffer aus den provider mappings - * sondern schaut falls nötig auch nach Oberklassen bzw. Interfaces. - * - * @param string $type - * - * @return mixed - */ - protected function getProviderMapping($type) - { - $providerMapping = $this->getProviderMappings(); - - if (isset($providerMapping[$type])) { - return $providerMapping[$type]; - } - - foreach ($this->getParentClassesAndInterfaces($type) as $class) { - if (isset($providerMapping[$class])) { - return $providerMapping[$class]; - } - } - - return null; - } - - private function getParentClassesAndInterfaces($type) - { - return class_exists($type) ? @class_parents($type) + @class_implements($type) : []; - } - - /** - * @deprecated use `createSchemaFromCallable` method instead - * - * @param Closure $closure - * - * @return SchemaProviderInterface - */ - protected function createSchemaFromClosure(\Closure $closure) - { - $schema = $closure($this->getFactory(), $this); - - return $schema; - } - - /** - * @param callable $callable - * - * @return SchemaProviderInterface - */ - protected function createSchemaFromCallable(callable $callable) - { - $schema = $callable instanceof \Closure ? - $this->createSchemaFromClosure($callable) : call_user_func($callable, $this->getFactory(), $this); - - return $schema; - } - - /** - * @param string $className - * - * @return SchemaProviderInterface - */ - protected function createSchemaFromClassName($className) - { - $schema = new $className($this->getFactory(), $this); - - return $schema; - } -} diff --git a/lib/classes/JsonApi/JsonApiIntegration/EncoderParser.php b/lib/classes/JsonApi/JsonApiIntegration/EncoderParser.php deleted file mode 100644 index 2e047b78ae6a55a88d60e0e60d848dab0e583dd7..0000000000000000000000000000000000000000 --- a/lib/classes/JsonApi/JsonApiIntegration/EncoderParser.php +++ /dev/null @@ -1,49 +0,0 @@ -<?php - -namespace JsonApi\JsonApiIntegration; - -use SimpleORMap; -use Neomerx\JsonApi\Encoder\Parser\Parser as NeomerxParser; - -/** - * Eine Instanz von Neomerx\JsonApi\Encoder\Parser\Parser wird - * benötigt, um Werte, die an den JSON-API-Encoder gehen, zu - * analysieren und entsprechned weiter zu verarbeiten. Unter anderem - * wird darin auch die Unterscheidung getroffen, ob Werte, die an den - * JSON-API-Encoder gehen, Collections sind oder nicht. - * - * Bei dieser Analyse werden sinnvollerweise alle Werte, die das - * PHP-Interface \IteratorAggregate implementieren, als Collections - * behandelt. Da aber die Stud.IP-Klasse \SimpleORMap - * ungewöhnlicherweise ebenfalls dieses Interface implementiert, muss - * hier eine Sonderbehandlung stattfinden. - * - * Dazu wird die Methode - * Neomerx\JsonApi\Encoder\Parser\Parser::analyzeCurrentData so - * überschrieben, dass Instanzen von \SimpleORMap nicht als - * Collections gelten. - * - * @see Neomerx\JsonApi\Encoder\Parser\Parser - * @see \SimpleORMap - */ -class EncoderParser extends NeomerxParser -{ - /** - * {@inheritdoc} - */ - protected function analyzeCurrentData() - { - $relationship = $this->stack->end()->getRelationship(); - $data = $relationship->isShowData() === true ? $relationship->getData() : null; - - if ($data instanceof SimpleORMap) { - $isEmpty = false; - $isCollection = false; - $traversableData = [$data]; - - return [$isEmpty, $isCollection, $traversableData]; - } - - return parent::analyzeCurrentData(); - } -} diff --git a/lib/classes/JsonApi/JsonApiIntegration/Factory.php b/lib/classes/JsonApi/JsonApiIntegration/Factory.php index 8e99d3b8ebac901b1da7955f12b099ae6d128b08..afdd4317a162ffbca9da37cdd84fad0527d9475a 100644 --- a/lib/classes/JsonApi/JsonApiIntegration/Factory.php +++ b/lib/classes/JsonApi/JsonApiIntegration/Factory.php @@ -2,9 +2,12 @@ namespace JsonApi\JsonApiIntegration; +use Neomerx\JsonApi\Contracts\Parser\EditableContextInterface; +use Neomerx\JsonApi\Contracts\Parser\ParserInterface; +use Neomerx\JsonApi\Contracts\Schema\LinkInterface; +use Neomerx\JsonApi\Contracts\Schema\SchemaContainerInterface; use Neomerx\JsonApi\Factories\Factory as NeomerxFactory; -use Neomerx\JsonApi\Contracts\Schema\ContainerInterface; -use Neomerx\JsonApi\Contracts\Encoder\Parser\ParserManagerInterface; +use Neomerx\JsonApi\Schema\Link; /** * Die "normale" \Neomerx\JsonApi\Factories\Factory stellt in @@ -19,38 +22,21 @@ use Neomerx\JsonApi\Contracts\Encoder\Parser\ParserManagerInterface; */ class Factory extends NeomerxFactory { - private $diContainer; - - public function setDependencyInjectionContainer(\Psr\Container\ContainerInterface $diContainer) - { - $this->diContainer = $diContainer; - } - - public function getDependencyInjectionContainer() - { - return $this->diContainer; - } - /** - * {@inheritdoc} + * @inheritdoc */ - public function createContainer(array $providers = []) - { - $container = new Container($this, $providers); - - $container->setLogger($this->logger); - - return $container; + public function createParser( + SchemaContainerInterface $container, + EditableContextInterface $context + ): ParserInterface { + return new Parser($this, $container, $context); } /** - * {@inheritdoc} + * @inheritdoc */ - public function createParser(ContainerInterface $container, ParserManagerInterface $manager) + public function createSchemaContainer(iterable $schemas): SchemaContainerInterface { - $parser = new EncoderParser($this, $this, $this, $container, $manager); - $parser->setLogger($this->logger); - - return $parser; + return new SchemaContainer($this, $schemas); } } diff --git a/lib/classes/JsonApi/JsonApiIntegration/JsonApiTrait.php b/lib/classes/JsonApi/JsonApiIntegration/JsonApiTrait.php deleted file mode 100644 index 3a5e122fe07899c2092c0712383a33d849314daf..0000000000000000000000000000000000000000 --- a/lib/classes/JsonApi/JsonApiIntegration/JsonApiTrait.php +++ /dev/null @@ -1,428 +0,0 @@ -<?php - -namespace JsonApi\JsonApiIntegration; - -use JsonApi\Middlewares\Authentication; -use Neomerx\JsonApi\Contracts\Factories\FactoryInterface; -use Neomerx\JsonApi\Contracts\Codec\CodecMatcherInterface; -use Neomerx\JsonApi\Contracts\Parameters\ParametersInterface; -use Neomerx\JsonApi\Contracts\Parameters\ParametersCheckerInterface; -use Neomerx\JsonApi\Contracts\Http\ResponsesInterface; -use Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface; -use Neomerx\JsonApi\Contracts\Http\Headers\HeaderParametersInterface; -use Neomerx\JsonApi\Contracts\Schema\ContainerInterface; -use Psr\Http\Message\ServerRequestInterface as Request; - -/** - * Dieser Trait beinhaltet Instanzmethoden und -variablen, die in - * JSON-API-Routen verwendet werden können, um entsprechende - * JSON-API-Responses zu generieren. - * - * @author info@neomerx.com (www.neomerx.com) - * @author mlunzena@uos.de - * - * @see https://github.com/InactiveProjects/limoncello/blob/v0.5.1/src/Http/JsonApiTrait.php - */ -trait JsonApiTrait -{ - /** - * If unrecognized parameters should be allowed in input parameters. - * - * @var bool - */ - protected $allowUnrecognizedParams = false; - - /** - * A list of allowed include paths in input parameters. - * - * Empty array [] means clients are not allowed to specify include paths and 'null' means all paths are allowed. - * - * @var string[]|null - */ - protected $allowedIncludePaths = []; - - /** - * A list of JSON API types which clients can sent field sets to. - * - * Possible values - * - * $allowedFieldSetTypes = null; // <-- for all types all fields are allowed - * - * $allowedFieldSetTypes = []; // <-- non of the types and fields are allowed - * - * $allowedFieldSetTypes = [ - * 'people' => null, // <-- all fields for 'people' are allowed - * 'comments' => [], // <-- no fields for 'comments' are allowed (all denied) - * 'posts' => ['title', 'body'], // <-- only 'title' and 'body' fields are allowed for 'posts' - * ]; - * - * @var array|null - */ - protected $allowedFieldSetTypes = null; - - /** - * A list of allowed sort field names in input parameters. - * - * Empty array [] means clients are not allowed to specify sort fields and 'null' means all fields are allowed. - * - * @var string[]|null - */ - protected $allowedSortFields = []; - - /** - * A list of allowed pagination input parameters (e.g 'number', 'size', 'offset' and etc). - * - * Empty array [] means clients are not allowed to specify paging and 'null' means all parameters are allowed. - * - * @var string[]|null - */ - protected $allowedPagingParameters = []; - - /** - * A list of allowed filtering input parameters. - * - * Empty array [] means clients are not allowed to specify filtering and 'null' means all parameters are allowed. - * - * @var string[]|null - */ - protected $allowedFilteringParameters = []; - - /** - * @var Psr\Container\ContainerInterface; - */ - protected $container; - - /** - * @var ParametersCheckerInterface - */ - private $parametersChecker; - - /** - * @var bool - */ - private $parametersChecked = false; - - /** - * Init integrations with JSON API implementation. - * - * @param $container - */ - private function initJsonApiSupport($container) - { - $this->container = $container; - - $factory = $container[FactoryInterface::class]; - - $this->parametersChecker = $factory->createQueryChecker( - $this->allowUnrecognizedParams, - $this->allowedIncludePaths, - $this->allowedFieldSetTypes, - $this->allowedSortFields, - $this->allowedPagingParameters, - $this->allowedFilteringParameters - ); - } - - // ***** RESPONSE GENERATORS ***** - - /** - * Get response with HTTP code only. - * - * @param $statusCode - * - * @return Response - */ - protected function getCodeResponse($statusCode, array $headers = []) - { - $this->checkQueryParameters(); - $responses = $this->container[ResponsesInterface::class]; - - return $responses->getCodeResponse($statusCode, $headers); - } - - /** - * Get response with meta information only. - * - * @param array|object $meta Meta information - * @param int $statusCode - * - * @return Response - */ - protected function getMetaResponse($meta, $statusCode = ResponsesInterface::HTTP_OK, $headers = []) - { - $this->checkQueryParameters(); - $responses = $this->container[ResponsesInterface::class]; - - return $responses->getMetaResponse($meta, $statusCode, $headers); - } - - /** - * Get response with regular JSON API Document in body. - * - * @param object|array $data - * @param int $statusCode - * @param array<string,\Neomerx\JsonApi\Contracts\Schema\LinkInterface>|null $links - * @param mixed $meta - * - * @return Response - */ - protected function getContentResponse( - $data, - $statusCode = ResponsesInterface::HTTP_OK, - $links = null, - $meta = null, - array $headers = [] - ) { - $this->checkQueryParameters(); - $responses = $this->container[ResponsesInterface::class]; - - return $responses->getContentResponse($data, $statusCode, $links, $meta, $headers); - } - - /** - * Get response with only resource identifiers. - * - * @param object|array $data - * @param int $statusCode - * @param array|null $links - * @param mixed $meta - * @param array $headers - * - * @return mixed - */ - protected function getIdentifiersResponse( - $data, - $links = null, - $meta = null, - array $headers = [] - ) { - $this->checkQueryParameters(); - $responses = $this->container[ResponsesInterface::class]; - $statusCode = ResponsesInterface::HTTP_OK; - - return $responses->getIdentifiersResponse($data, $statusCode, $links, $meta, $headers); - } - - protected function getPaginatedIdentifiersResponse( - $data, - $total, - $links = null, - $meta = null, - array $headers = [] - ) { - $this->checkQueryParameters(); - $responses = $this->container[ResponsesInterface::class]; - $statusCode = ResponsesInterface::HTTP_OK; - - list($offset, $limit) = $this->getOffsetAndLimit(); - - if (!$meta) { - $meta = []; - } - - $meta['page'] = [ - 'offset' => (int) $offset, - 'limit' => (int) $limit, - ]; - - if (isset($total)) { - $meta['page']['total'] = (int) $total; - } - - $paginator = new Paginator($total, $offset, $limit); - - if (!$links) { - $links = []; - } - - foreach (words('first last prev next') as $rel) { - if (list($off, $lim) = $paginator->{'get'.ucfirst($rel).'PageOffsetAndLimit'}()) { - $links[$rel] = $this->createLink($off, $lim); - } - } - - return $responses->getIdentifiersResponse($data, $statusCode, $links, $meta, $headers); - } - - /** - * @param object $resource - * @param array<string,\Neomerx\JsonApi\Contracts\Schema\LinkInterface>|null $links - * @param mixed $meta - * - * @return Response - */ - protected function getCreatedResponse( - $resource, - $links = null, - $meta = null, - array $headers = [] - ) { - $this->checkQueryParameters(); - $responses = $this->container[ResponsesInterface::class]; - - return $responses->getCreatedResponse($resource, $links, $meta, $headers); - } - - protected function getPaginatedContentResponse( - $data, - $total, - $statusCode = ResponsesInterface::HTTP_OK, - $links = null, - $meta = null, - array $headers = [] - ) { - $this->checkQueryParameters(); - $responses = $this->container[ResponsesInterface::class]; - - list($offset, $limit) = $this->getOffsetAndLimit(); - - if (!$meta) { - $meta = []; - } - - $meta['page'] = [ - 'offset' => (int) $offset, - 'limit' => (int) $limit, - ]; - - if (isset($total)) { - $meta['page']['total'] = (int) $total; - } - - $paginator = new Paginator($total, $offset, $limit); - - if (!$links) { - $links = []; - } - - foreach (words('first last prev next') as $rel) { - if (list($off, $lim) = $paginator->{'get'.ucfirst($rel).'PageOffsetAndLimit'}()) { - $links[$rel] = $this->createLink($off, $lim); - } - } - - return $responses->getContentResponse($data, $statusCode, $links, $meta, $headers); - } - - /** - * @return mixed - */ - protected function getDocument() - { - $request = $this->container['request']; - $codecMatcher = $this->container[CodecMatcherInterface::class]; - if ($codecMatcher->getDecoder() === null) { - $parameters = $this->container[HeaderParametersInterface::class]; - $codecMatcher->matchDecoder($parameters->getContentTypeHeader()); - } - $decoder = $codecMatcher->getDecoder(); - - return $decoder->decode($request->getBody()->getContents()); - } - - protected function checkQueryParameters() - { - $this->parametersChecker->checkQuery($this->container[EncodingParametersInterface::class]); - $this->parametersChecked = true; - } - - /** - * @return ParametersInterface - */ - protected function getQueryParameters() - { - if ($this->parametersChecked === false) { - $this->checkQueryParameters(); - } - - return $this->container[EncodingParametersInterface::class]; - } - - /** - * Liefert Offset und Limit aus den Request-Parametern zurück. - * - * @param int $offsetDefault optional; gibt den Standard-Offset - * an, falls dieser Wert nicht im Request gesetzt ist - * @param int $limitDefault optional; gibt das Standard-Limit an, - * falls dieser Wert nicht im Request gesetzt ist - * - * @return array { - * - * @var int $offset der im Request gesetzte Offset oder - * ansonsten der Default-Wert 0 - * @var int $limit das im Request gesetzte Limit oder - * ansonsten der Default-Wert 30 - * } - */ - protected function getOffsetAndLimit($offsetDefault = 0, $limitDefault = 30) - { - $params = $this->getQueryParameters()->getPaginationParameters(); - - return [ - $params && array_key_exists('offset', $params) ? (int) $params['offset'] : $offsetDefault, - $params && array_key_exists('limit', $params) ? (int) $params['limit'] : $limitDefault, - ]; - } - - private function createLink($offset, $limit) - { - $factory = $this->container[FactoryInterface::class]; - $request = $this->container['request']; - - $queryParams = $request->getQueryParams(); - $queryParams['page']['offset'] = $offset; - $queryParams['page']['limit'] = $limit; - - $uri = $request->getUri()->withQuery(http_build_query($queryParams)); - - $basePath = $uri->getBasePath(); - $path = $uri->getPath(); - $query = $uri->getQuery(); - $fragment = $uri->getFragment(); - - $uriString = $basePath.'/'.ltrim($path, '/') - .($query ? '?'.$query : '') - .($fragment ? '#'.$fragment : ''); - - return $factory->createLink($uriString, null, true); - } - - /** - * Gibt null oder das User-Objekt des "eingeloggten" Nutzers zurück. - * - * @param request Request der eingehende Request - * - * @return mixed entweder null oder das User-Objekt des - * "eingeloggten" Nutzers - */ - public function getUser(Request $request) - { - return $request->getAttribute(Authentication::USER_KEY, null); - } - - /** - * Gibt das Schema zu einer beliebigen Ressource zurück. - * - * @param resource Object die Ressource, zu der das Schema geliefert werden soll - * - * @return SchemaProviderInterface das Schema zur Ressource - */ - protected function getSchema($resource) - { - return $this->container[ContainerInterface::class]->getSchema($resource); - } - - /** - * Ermöglicht JSON-Routen das ermitteln der resource location URL - * eines Objekts. - * - * @param resource Object die Ressource zu der die URL gefunden - * werden soll - * - * @retunr String die resource location URL - */ - protected function getResourceLocationUrl($resource) - { - return $this->container[ResponsesInterface::class]->getResourceLocationUrl($resource); - } -} diff --git a/lib/classes/JsonApi/JsonApiIntegration/Paginator.php b/lib/classes/JsonApi/JsonApiIntegration/Paginator.php index 09f8fc8f0da2fc7db8ca54440ea91dffefb80363..7e74f8066000a20c0771f7860d412e7d6cfb98b2 100644 --- a/lib/classes/JsonApi/JsonApiIntegration/Paginator.php +++ b/lib/classes/JsonApi/JsonApiIntegration/Paginator.php @@ -11,6 +11,20 @@ namespace JsonApi\JsonApiIntegration; */ class Paginator { + /** @var int|null */ + private $total; + + /** @var int */ + private $offset; + + /** @var int */ + private $limit; + + /** + * @param int|null $total + * @param int $offset + * @param int $limit + */ public function __construct($total, $offset, $limit) { $this->total = $total; @@ -18,16 +32,16 @@ class Paginator $this->limit = $limit; } - public function getFirstPageOffsetAndLimit() + public function getFirstPageOffsetAndLimit(): array { - if ($this->limit === 0) { + if (0 === $this->limit) { return [0, 0]; } return [0, $this->limit]; } - public function getLastPageOffsetAndLimit() + public function getLastPageOffsetAndLimit(): ?array { if (!isset($this->total)) { return null; @@ -42,7 +56,7 @@ class Paginator return [$last, $this->limit]; } - public function getPrevPageOffsetAndLimit() + public function getPrevPageOffsetAndLimit(): ?array { if ($this->limit === 0) { return null; @@ -55,7 +69,7 @@ class Paginator return [max(0, $this->offset - $this->limit), $this->limit]; } - public function getNextPageOffsetAndLimit() + public function getNextPageOffsetAndLimit(): ?array { if ($this->limit === 0) { return null; diff --git a/lib/classes/JsonApi/JsonApiIntegration/Parser.php b/lib/classes/JsonApi/JsonApiIntegration/Parser.php new file mode 100644 index 0000000000000000000000000000000000000000..6e460d9a9917117f629f77751a84728d4f22fc8c --- /dev/null +++ b/lib/classes/JsonApi/JsonApiIntegration/Parser.php @@ -0,0 +1,75 @@ +<?php + +namespace JsonApi\JsonApiIntegration; + +use Neomerx\JsonApi\Contracts\Factories\FactoryInterface; +use Neomerx\JsonApi\Contracts\Schema\SchemaContainerInterface; +use Neomerx\JsonApi\Contracts\Parser\EditableContextInterface; +use Neomerx\JsonApi\Exceptions\InvalidArgumentException; +use Neomerx\JsonApi\Parser\Parser as NeomerxParser; +use SimpleORMap; +use function Neomerx\JsonApi\I18n\format as _; + +/** + * Eine Instanz von Neomerx\JsonApi\Encoder\Parser\Parser wird + * benötigt, um Werte, die an den JSON-API-Encoder gehen, zu + * analysieren und entsprechned weiter zu verarbeiten. Unter anderem + * wird darin auch die Unterscheidung getroffen, ob Werte, die an den + * JSON-API-Encoder gehen, Collections sind oder nicht. + * + * Bei dieser Analyse werden sinnvollerweise alle Werte, die das + * PHP-Interface \IteratorAggregate implementieren, als Collections + * behandelt. Da aber die Stud.IP-Klasse \SimpleORMap + * ungewöhnlicherweise ebenfalls dieses Interface implementiert, muss + * hier eine Sonderbehandlung stattfinden. + * + * Dazu wird die Methode + * Neomerx\JsonApi\Encoder\Parser\Parser::analyzeCurrentData so + * überschrieben, dass Instanzen von \SimpleORMap nicht als + * Collections gelten. + * + * @see Neomerx\JsonApi\Parser\Parser + * @see \SimpleORMap + */ +class Parser extends NeomerxParser +{ + /** + * @var SchemaContainerInterface + */ + private $schemaContainer; + + /** + * As `$schemaContainer` is private in \Neomerx\JsonApi\Parser\Parser it has + * to be stored again in this subclass. + * + * @param FactoryInterface $factory + * @param SchemaContainerInterface $container + * @param EditableContextInterface $context + */ + public function __construct( + FactoryInterface $factory, + SchemaContainerInterface $container, + EditableContextInterface $context + ) { + $this->schemaContainer = $container; + + parent::__construct($factory, $container, $context); + } + + /** + * Show better error messages using instances of subclasses of \SimpleORMap + * without a Schema. + * + * @inheritdoc + */ + public function parse($data, array $paths = []): iterable + { + \assert(\is_array($data) === true || \is_object($data) === true || $data === null); + + if ($data instanceof SimpleORMap && $this->schemaContainer->hasSchema($data) !== true) { + throw new InvalidArgumentException(_(static::MSG_NO_SCHEMA_FOUND, \get_class($data))); + } + + return parent::parse($data, $paths); + } +} diff --git a/lib/classes/JsonApi/JsonApiIntegration/QueryChecker.php b/lib/classes/JsonApi/JsonApiIntegration/QueryChecker.php new file mode 100644 index 0000000000000000000000000000000000000000..ff2a03d26deae9f263fbb9f967456a7a7a07b3a9 --- /dev/null +++ b/lib/classes/JsonApi/JsonApiIntegration/QueryChecker.php @@ -0,0 +1,186 @@ +<?php + +namespace JsonApi\JsonApiIntegration; + +use Neomerx\JsonApi\Exceptions\JsonApiException; +use Neomerx\JsonApi\Schema\ErrorCollection; + +class QueryChecker +{ + /** + * @var bool + */ + private $allowUnrecognized; + + /** + * @var array|null + */ + private $includePaths; + + /** + * @var array|null + */ + private $fieldSetTypes; + + /** + * @var array|null + */ + private $pagingParameters; + + /** + * @var array|null + */ + private $sortParameters; + + /** + * @var array|null + */ + private $filteringParameters; + + public function __construct( + bool $allowUnrecognized = true, + array $includePaths = null, + array $fieldSetTypes = null, + array $sortParameters = null, + array $pagingParameters = null, + array $filteringParameters = null + ) { + $this->includePaths = $includePaths; + $this->allowUnrecognized = $allowUnrecognized; + $this->fieldSetTypes = $fieldSetTypes; + $this->sortParameters = $this->flip($sortParameters); + $this->pagingParameters = $this->flip($pagingParameters); + $this->filteringParameters = $this->flip($filteringParameters); + } + + public function checkQuery(QueryParserInterface $queryParser): void + { + $errors = new ErrorCollection(); + + $this->checkIncludePaths($errors, $queryParser); + $this->checkFieldSets($errors, $queryParser); + $this->checkFiltering($errors, $queryParser); + $this->checkSorting($errors, $queryParser); + $this->checkPaging($errors, $queryParser); + $this->checkUnrecognized($errors, $queryParser); + + if ($errors->count()) { + throw new JsonApiException($errors, JsonApiException::HTTP_CODE_BAD_REQUEST); + } + } + + protected function checkIncludePaths(ErrorCollection $errors, QueryParserInterface $queryParser): void + { + $withinAllowed = $this->valuesWithinAllowed( + iterator_to_array($queryParser->getIncludePaths()), + $this->includePaths + ); + if (!$withinAllowed) { + $errors->addQueryParameterError( + QueryParser::PARAM_INCLUDE, + 'Include paths should contain only allowed ones.' + ); + } + } + + protected function checkFieldSets(ErrorCollection $errors, QueryParserInterface $queryParser): void + { + $withinAllowed = $this->isFieldsAllowed(iterator_to_array($queryParser->getFields())); + if (!$withinAllowed) { + $errors->addQueryParameterError(QueryParser::PARAM_FIELDS, 'Field sets should contain only allowed ones.'); + } + } + + protected function checkFiltering(ErrorCollection $errors, QueryParserInterface $queryParser): void + { + $withinAllowed = $this->keysWithinAllowed( + iterator_to_array($queryParser->getFilters()), + $this->filteringParameters + ); + if (!$withinAllowed) { + $errors->addQueryParameterError(QueryParser::PARAM_FILTER, 'Filter should contain only allowed values.'); + } + } + + protected function checkSorting(ErrorCollection $errors, QueryParserInterface $queryParser): void + { + if (null !== $queryParser->getSorts() && null !== $this->sortParameters) { + foreach ($queryParser->getSorts() as $sortParameter) { + if (!array_key_exists($sortParameter->getField(), $this->sortParameters)) { + $errors->addQueryParameterError( + QueryParser::PARAM_SORT, + sprintf('Sort parameter %s is not allowed.', $sortParameter->getField()) + ); + } + } + } + } + + protected function checkPaging(ErrorCollection $errors, QueryParserInterface $queryParser): void + { + $withinAllowed = $this->keysWithinAllowed( + iterator_to_array($queryParser->getPagination()), + $this->pagingParameters + ); + if (!$withinAllowed) { + $errors->addQueryParameterError( + QueryParser::PARAM_PAGE, + 'Page parameter should contain only allowed values.' + ); + } + } + + protected function checkUnrecognized(ErrorCollection $errors, QueryParserInterface $queryParser): void + { + if (!$this->allowUnrecognized && !empty($queryParser->getUnrecognizedParameters())) { + foreach ($queryParser->getUnrecognizedParameters() as $name => $value) { + $errors->addQueryParameterError($name, 'Unrecognized Parameter.'); + } + } + } + + private function keysWithinAllowed(array $toCheck = null, array $allowed = null): bool + { + return null === $toCheck || null === $allowed || empty(array_diff_key($toCheck, $allowed)); + } + + private function valuesWithinAllowed(array $toCheck = null, array $allowed = null): bool + { + return null === $toCheck || null === $allowed || empty(array_diff($toCheck, $allowed)); + } + + /** + * @return array|null + */ + private function flip(array $array = null) + { + return $array === null ? null : array_flip($array); + } + + /** + * Check input fields against allowed. + * + * @param array|null $fields + */ + private function isFieldsAllowed(array $fields = null): bool + { + if ($this->fieldSetTypes === null || $fields === null) { + return true; + } + + foreach ($fields as $type => $requestedFields) { + if (array_key_exists($type, $this->fieldSetTypes) === false) { + return false; + } + + $allowedFields = $this->fieldSetTypes[$type]; + + // if not all fields are allowed and requested more fields than allowed + if ($allowedFields !== null && empty(array_diff($requestedFields, $allowedFields)) === false) { + return false; + } + } + + return true; + } +} diff --git a/lib/classes/JsonApi/JsonApiIntegration/QueryParser.php b/lib/classes/JsonApi/JsonApiIntegration/QueryParser.php new file mode 100644 index 0000000000000000000000000000000000000000..a33979e2a091852e66d008b52a99517333315952 --- /dev/null +++ b/lib/classes/JsonApi/JsonApiIntegration/QueryParser.php @@ -0,0 +1,76 @@ +<?php + +namespace JsonApi\JsonApiIntegration; + +use Neomerx\JsonApi\Contracts\Http\Query\BaseQueryParserInterface as P; +use Neomerx\JsonApi\Http\Query\BaseQueryParser; +use Neomerx\JsonApi\Exceptions\JsonApiException; +use Neomerx\JsonApi\Schema\Error; + +/** + */ +class QueryParser extends BaseQueryParser implements QueryParserInterface +{ + public function getFilteringParameters(): array + { + return iterator_to_array($this->getFilters()); + } + + public function getFilters(): iterable + { + $parameters = $this->getParameters(); + if (array_key_exists(P::PARAM_FILTER, $parameters)) { + $filters = $parameters[P::PARAM_FILTER]; + if (!is_array($filters) || empty($filters)) { + $errorTitle = $this->getMessage(static::MSG_ERR_INVALID_PARAMETER); + $error = new Error(null, null, null, null, null, $errorTitle, null, [ + Error::SOURCE_PARAMETER => P::PARAM_FILTER, + ]); + throw new JsonApiException($error); + } + + foreach ($filters as $type => $field) { + yield $type => $field; + } + } + } + + /** + * Get pagination parameters from encoder. + * + * @return iterable + */ + public function getPagination(): iterable + { + $parameters = $this->getParameters(); + if (array_key_exists(P::PARAM_PAGE, $parameters)) { + $pagination = $parameters[P::PARAM_PAGE]; + if (!is_array($pagination) || empty($pagination)) { + $errorTitle = $this->getMessage(static::MSG_ERR_INVALID_PARAMETER); + $error = new Error(null, null, null, null, null, $errorTitle, null, [ + Error::SOURCE_PARAMETER => P::PARAM_PAGE, + ]); + throw new JsonApiException($error); + } + + foreach ($pagination as $type => $field) { + yield $type => $field; + } + } + } + + public function getUnrecognizedParameters(): iterable + { + $parameters = $this->getParameters(); + $supported = [ + P::PARAM_INCLUDE => 0, + P::PARAM_FIELDS => 0, + P::PARAM_PAGE => 0, + P::PARAM_FILTER => 0, + P::PARAM_SORT => 0, + ]; + $unrecognized = array_diff_key($parameters, $supported); + + return $unrecognized; + } +} diff --git a/lib/classes/JsonApi/JsonApiIntegration/QueryParserInterface.php b/lib/classes/JsonApi/JsonApiIntegration/QueryParserInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..ad37cb7a08f951bc810b2b56bfafc95b129d6e11 --- /dev/null +++ b/lib/classes/JsonApi/JsonApiIntegration/QueryParserInterface.php @@ -0,0 +1,25 @@ +<?php + +namespace JsonApi\JsonApiIntegration; + +use Neomerx\JsonApi\Contracts\Http\Query\BaseQueryParserInterface; + +interface QueryParserInterface extends BaseQueryParserInterface +{ + /** Query parameter */ + const PARAM_PAGING_LIMIT = 'limit'; + + /** Query parameter */ + const PARAM_PAGING_OFFSET = 'offset'; + + public function getIncludePaths(): iterable; + + public function getFilters(): iterable; + + /** + * @return iterable + */ + public function getPagination(): iterable; + + public function getUnrecognizedParameters(): iterable; +} diff --git a/lib/classes/JsonApi/JsonApiIntegration/Responses.php b/lib/classes/JsonApi/JsonApiIntegration/Responses.php index e2f6b54bd73f9feeabc95feac0a71e5be5e46832..0b8ccb559eb3ca151949125f83c6408a3fbf3807 100644 --- a/lib/classes/JsonApi/JsonApiIntegration/Responses.php +++ b/lib/classes/JsonApi/JsonApiIntegration/Responses.php @@ -2,27 +2,23 @@ namespace JsonApi\JsonApiIntegration; +use Neomerx\JsonApi\Http\BaseResponses; use Neomerx\JsonApi\Contracts\Encoder\EncoderInterface; -use Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface; use Neomerx\JsonApi\Contracts\Http\Headers\MediaTypeInterface; +use Slim\Psr7\Headers; +use Slim\Psr7\Response; + +use Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface; use Neomerx\JsonApi\Contracts\Http\Headers\SupportedExtensionsInterface; use Neomerx\JsonApi\Contracts\Schema\ContainerInterface; -use Neomerx\JsonApi\Http\Responses as NeomerxResponses; -use Slim\Http\Headers; -use Slim\Http\Response; /** * Diese Factory-Klasse verknüpft die "neomerx/json-api"-Bibliothek mit der * Slim-Applikation. Hier wird festgelegt, wie Slim-artige Response-Objekte gebildet * werden. */ -class Responses extends NeomerxResponses +class Responses extends BaseResponses { - /** - * @var EncodingParametersInterface|null - */ - private $parameters; - /** * @var EncoderInterface */ @@ -33,48 +29,12 @@ class Responses extends NeomerxResponses */ private $outputMediaType; - /** - * @var SupportedExtensionsInterface - */ - private $extensions; - - /** - * @var ContainerInterface - */ - private $schemes; - - /** - * @var null|string - */ - private $urlPrefix; - - /** - * Dieser Konstruktor wird in \JsonApi\Providers\JsonApiServices - * befüllt. - * - * @param MediaTypeInterface $outputMediaType - * @param SupportedExtensionsInterface $extensions - * @param EncoderInterface $encoder - * @param ContainerInterface $schemes - * @param EncodingParametersInterface|null $parameters - * @param string|null $urlPrefix - * - * @internal - */ public function __construct( - MediaTypeInterface $outputMediaType, - SupportedExtensionsInterface $extensions, EncoderInterface $encoder, - ContainerInterface $schemes, - EncodingParametersInterface $parameters = null, - $urlPrefix = null + MediaTypeInterface $outputMediaType ) { - $this->extensions = $extensions; $this->encoder = $encoder; $this->outputMediaType = $outputMediaType; - $this->schemes = $schemes; - $this->urlPrefix = $urlPrefix; - $this->parameters = $parameters; } /** @@ -87,13 +47,13 @@ class Responses extends NeomerxResponses * zukünftigen Response * @param array $headers die Header der zukünftigen Response * - * @return \Slim\Http\Response die fertige Slim-Response + * @return mixed die fertige Slim-Response */ - protected function createResponse($content, $statusCode, array $headers) + protected function createResponse(?string $content, int $statusCode, array $headers) { $headers = new Headers($headers); $response = new Response($statusCode, $headers); - $response->getBody()->write($content); + $response->getBody()->write($content ?? ''); return $response->withProtocolVersion('1.1'); } @@ -103,7 +63,7 @@ class Responses extends NeomerxResponses * * @internal */ - protected function getEncoder() + protected function getEncoder(): EncoderInterface { return $this->encoder; } @@ -113,77 +73,8 @@ class Responses extends NeomerxResponses * * @internal */ - protected function getUrlPrefix() - { - return $this->urlPrefix; - } - - /** - * {@inheritdoc} - * - * @internal - */ - protected function getEncodingParameters() - { - return $this->parameters; - } - - /** - * {@inheritdoc} - * - * @internal - */ - protected function getSchemaContainer() - { - return $this->schemes; - } - - /** - * {@inheritdoc} - * - * @internal - */ - protected function getSupportedExtensions() - { - return $this->extensions; - } - - /** - * {@inheritdoc} - * - * @internal - */ - protected function getMediaType() + protected function getMediaType(): MediaTypeInterface { return $this->outputMediaType; } - - /** - * {@inheritdoc} - */ - public function getIdentifiersResponse( - $data, - $statusCode = self::HTTP_OK, - $links = null, - $meta = null, - array $headers = [] - ) { - $encoder = $this->getEncoder(); - - $links === null ?: $encoder->withLinks($links); - $meta === null ?: $encoder->withMeta($meta); - $content = $encoder->encodeIdentifiers($data, $this->getEncodingParameters()); - - return $this->createJsonApiResponse($content, $statusCode, $headers); - } - - /** - * Widen method visibility from protected to public. - * - * {@inheritdoc} - */ - public function getResourceLocationUrl($resource) - { - return parent::getResourceLocationUrl($resource); - } } diff --git a/lib/classes/JsonApi/JsonApiIntegration/SchemaContainer.php b/lib/classes/JsonApi/JsonApiIntegration/SchemaContainer.php new file mode 100644 index 0000000000000000000000000000000000000000..a299084563203a0a63b4414ef99bead910a9d2a4 --- /dev/null +++ b/lib/classes/JsonApi/JsonApiIntegration/SchemaContainer.php @@ -0,0 +1,104 @@ +<?php + +namespace JsonApi\JsonApiIntegration; + +use Closure; +use Neomerx\JsonApi\Contracts\Schema\SchemaInterface; +use Neomerx\JsonApi\Exceptions\InvalidArgumentException; +use function Neomerx\JsonApi\I18n\format as _; +use Neomerx\JsonApi\Schema\SchemaContainer as NeomerxSchemaContainer; + +class SchemaContainer extends NeomerxSchemaContainer +{ + /** + * The original SchemaContainer does not like mappings of interfaces to schemas. + * So this method now allows classes *and* interfaces. + * + * @inheritdoc + */ + public function register(string $type, $schema): void + { + if (true === empty($type) || (false === \class_exists($type) && false === \interface_exists($type))) { + throw new InvalidArgumentException(_(static::MSG_INVALID_MODEL_TYPE)); + } + + $isOk = + (true === \is_string($schema) && + false === empty($schema) && + true === \class_exists($schema) && + true === \in_array(SchemaInterface::class, \class_implements($schema))) || + \is_callable($schema) || + $schema instanceof SchemaInterface; + if (false === $isOk) { + throw new InvalidArgumentException(_(static::MSG_INVALID_SCHEME, $type)); + } + + if (true === $this->hasProviderMapping($type)) { + throw new InvalidArgumentException(_(static::MSG_TYPE_REUSE_FORBIDDEN, $type)); + } + + if ($schema instanceof SchemaInterface) { + $this->setProviderMapping($type, \get_class($schema)); + $this->setResourceToJsonTypeMapping($schema->getType(), $type); + $this->setCreatedProvider($type, $schema); + } else { + $this->setProviderMapping($type, $schema); + } + } + + /** + * @param callable $callable + * + * @return SchemaInterface + */ + protected function createSchemaFromCallable(callable $callable): SchemaInterface + { + $schema = \call_user_func($callable, $this); + + return $schema; + } + + /** + * @param string $type + * + * @return bool + */ + protected function hasProviderMapping(string $type): bool + { + if (parent::hasProviderMapping($type)) { + return true; + } + + foreach ($this->getParentClassesAndInterfaces($type) as $class) { + if (parent::hasProviderMapping($class)) { + return true; + } + } + + return false; + } + + /** + * @param string $type + * + * @return mixed + */ + protected function getProviderMapping(string $type) + { + if (parent::hasProviderMapping($type)) { + return parent::getProviderMapping($type); + } + + foreach ($this->getParentClassesAndInterfaces($type) as $class) { + if (parent::hasProviderMapping($class)) { + return parent::getProviderMapping($class); + } + } + throw new InvalidArgumentException(_('Cannot find schema for type `%s`', $type)); + } + + private function getParentClassesAndInterfaces(string $type): array + { + return class_exists($type) ? @class_parents($type) + @class_implements($type) : []; + } +} diff --git a/lib/classes/JsonApi/Middlewares/Auth/HttpBasicAuthStrategy.php b/lib/classes/JsonApi/Middlewares/Auth/HttpBasicAuthStrategy.php index 57facebb0253ddae58556b61e7ed7ae182a842fd..42b18ae2ac57cc62bb8a38c5c3ea4c671bdc4610 100644 --- a/lib/classes/JsonApi/Middlewares/Auth/HttpBasicAuthStrategy.php +++ b/lib/classes/JsonApi/Middlewares/Auth/HttpBasicAuthStrategy.php @@ -2,15 +2,24 @@ namespace JsonApi\Middlewares\Auth; -use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface as Request; class HttpBasicAuthStrategy implements Strategy { - protected $user; + /** @var callable */ + protected $authenticator; + /** @var Request */ protected $request; + /** @var ?\User */ + protected $user; + + /** + * @param Request $request + * @param callable $authenticator + */ public function __construct(Request $request, $authenticator) { $this->request = $request; diff --git a/lib/classes/JsonApi/Middlewares/Auth/OAuth1Strategy.php b/lib/classes/JsonApi/Middlewares/Auth/OAuth1Strategy.php index 9d465ec3dca492163d6c20fea9309758854526dc..113ee09afe62ae429a4ccbe1fedeec75d550e325 100644 --- a/lib/classes/JsonApi/Middlewares/Auth/OAuth1Strategy.php +++ b/lib/classes/JsonApi/Middlewares/Auth/OAuth1Strategy.php @@ -2,15 +2,23 @@ namespace JsonApi\Middlewares\Auth; -use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface as Request; class OAuth1Strategy implements Strategy { - protected $user; + /** @var callable */ + protected $authenticator; + /** @var Request */ protected $request; + /** @var ?\User */ + protected $user; + + /** + * @param callable $authenticator + */ public function __construct(Request $request, $authenticator) { $this->request = $request; @@ -40,7 +48,7 @@ class OAuth1Strategy implements Strategy return $response; //->withHeader('WWW-Authenticate', sprintf('Basic realm="%s"', 'Stud.IP JSON-API')); } - private function detect() + private function detect(): ?\User { if (!\OAuthRequestVerifier::requestIsSigned()) { return null; @@ -75,10 +83,11 @@ class OAuth1Strategy implements Strategy return null; } + /** @var \User */ return \User::find($userId); } - private function getParamsFromAuthorizationHeader(Request $request, array $params) + private function getParamsFromAuthorizationHeader(Request $request, array $params): array { if ($request->hasHeader('Authorization')) { $auth = $request->getHeaderLine('Authorization'); diff --git a/lib/classes/JsonApi/Middlewares/Auth/SessionStrategy.php b/lib/classes/JsonApi/Middlewares/Auth/SessionStrategy.php index 101b172922923e586d78d928d854efcfd96aee77..26c0bc22fe621d33a3c596f6cfa43be284a04359 100644 --- a/lib/classes/JsonApi/Middlewares/Auth/SessionStrategy.php +++ b/lib/classes/JsonApi/Middlewares/Auth/SessionStrategy.php @@ -6,6 +6,7 @@ use Psr\Http\Message\ResponseInterface as Response; class SessionStrategy implements Strategy { + /** @var ?\User */ protected $user; public function check() @@ -22,7 +23,8 @@ class SessionStrategy implements Strategy return $this->user; } - $isAuthenticated = isset($GLOBALS['auth']) && $GLOBALS['auth']->is_authenticated() && 'nobody' !== $GLOBALS['user']->id; + $isAuthenticated = + isset($GLOBALS['auth']) && $GLOBALS['auth']->is_authenticated() && 'nobody' !== $GLOBALS['user']->id; if ($isAuthenticated) { $this->user = $GLOBALS['user']->getAuthenticatedUser(); diff --git a/lib/classes/JsonApi/Middlewares/Auth/Strategy.php b/lib/classes/JsonApi/Middlewares/Auth/Strategy.php index 69c92e56a3d44f45e3955b0bde8e739cc9ce8d00..6b26cedceb6cfc6e1f9a27576d5756a6e1cf4355 100644 --- a/lib/classes/JsonApi/Middlewares/Auth/Strategy.php +++ b/lib/classes/JsonApi/Middlewares/Auth/Strategy.php @@ -16,16 +16,16 @@ interface Strategy /** * Get the currently authenticated user. * - * @return \User|null + * @return ?\User */ public function user(); /** * Validate a user's credentials. * - * @param array $credentials + * @param Response $response the current response * - * @return bool + * @return Response the new response containing the challenge */ public function addChallenge(Response $response); } diff --git a/lib/classes/JsonApi/Middlewares/Authentication.php b/lib/classes/JsonApi/Middlewares/Authentication.php index 1608524a1b5387898ff58ba946ae5f1016211708..3e4ee176a78a4998c1f5cb18f71788f8676ecc37 100644 --- a/lib/classes/JsonApi/Middlewares/Authentication.php +++ b/lib/classes/JsonApi/Middlewares/Authentication.php @@ -2,18 +2,11 @@ namespace JsonApi\Middlewares; +use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface as Request; -use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Server\RequestHandlerInterface as RequestHandler; +use Slim\Psr7\Response; -/** - * Diese Klasse ist eine "leere" Middleware, die noch implementiert - * werden muss. - * - * Allerdings wird sie jetzt schon in \JsonApi\RouteMap - * verwendet, um dort die autorisierten Routen abzusichern. - * - * @todo muss zu einem späteren Zeitpunk implementiert werden - */ class Authentication { // der Schlüssel des Request-Attributs, in dem der Stud.IP-Nutzer @@ -24,14 +17,16 @@ class Authentication // a callable accepting two arguments username and password and // returning either null or a Stud.IP user object + /** @var callable */ private $authenticator; /** * Der Konstruktor. * - * @param callable $authenticator ein Callable, das den - * Nutzernamen und das Passwort als Argumente erhält und damit - * entweder einen Stud.IP-User-Objekt oder null zurückgibt + * @param callable $authenticator ein Callable, das den Nutzernamen und + * das Passwort als Argumente erhält und + * damit entweder einen Stud.IP-User-Objekt + * oder null zurückgibt */ public function __construct($authenticator) { @@ -41,17 +36,14 @@ class Authentication /** * Hier muss die Autorisierung implementiert werden. * - * @param \Psr\Http\Message\ServerRequestInterface $request das - * PSR-7 Request-Objekt - * @param \Psr\Http\Message\ResponseInterface $response das PSR-7 - * Response-Objekt - * @param callable $next das nächste Middleware-Callable + * @param Request $request das Request-Objekt + * @param RequestHandler $handler der PSR-15 Request Handler * - * @return \Psr\Http\Message\ResponseInterface das neue Response-Objekt + * @return ResponseInterface das neue Response-Objekt * * @SuppressWarnings(PHPMD.Superglobals) */ - public function __invoke(Request $request, Response $response, $next) + public function __invoke(Request $request, RequestHandler $handler) { $guards = [ new Auth\SessionStrategy(), @@ -63,17 +55,17 @@ class Authentication if ($guard->check()) { $request = $this->provideUser($request, $guard->user()); - return $next($request, $response); + return $handler->handle($request); } } - return $this->generateChallenges($response, $guards); + return $this->generateChallenges($guards); } // according to RFC 2616 - private function generateChallenges(Response $response, array $guards) + private function generateChallenges(array $guards): Response { - $response = $response->withStatus(401); + $response = new Response(401); foreach ($guards as $guard) { $response = $guard->addChallenge($response); @@ -85,10 +77,10 @@ class Authentication /** * @SuppressWarnings(PHPMD.Superglobals) */ - private function provideUser(Request $request, \User $user) + private function provideUser(Request $request, \User $user): Request { if ('nobody' === $GLOBALS['user']->id) { - $GLOBALS['user'] = new \Seminar_User($user->id); + $GLOBALS['user'] = new \Seminar_User($user); $GLOBALS['auth'] = new \Seminar_Auth(); $GLOBALS['auth']->auth = [ 'uid' => $user->id, diff --git a/lib/classes/JsonApi/Middlewares/DangerousRouteHandler.php b/lib/classes/JsonApi/Middlewares/DangerousRouteHandler.php index 4695242087d8da02eb5879b857fe8051e183a08b..8ff78803a07a7db6fae3c230c8a2e7990dae2278 100644 --- a/lib/classes/JsonApi/Middlewares/DangerousRouteHandler.php +++ b/lib/classes/JsonApi/Middlewares/DangerousRouteHandler.php @@ -2,31 +2,30 @@ namespace JsonApi\Middlewares; +use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface as Request; -use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Server\RequestHandlerInterface as RequestHandler; +use Slim\Psr7\Response; /** * TODO. */ class DangerousRouteHandler { - /** * TODO. * - * @param \Psr\Http\Message\ServerRequestInterface $request das - * PSR-7 Request-Objekt - * @param \Psr\Http\Message\ResponseInterface $response das PSR-7 - * Response-Objekt - * @param callable $next das nächste Middleware-Callable + * @param Request $request das Request-Objekt + * @param RequestHandler $handler der PSR-15 Request Handler * - * @return \Psr\Http\Message\ResponseInterface die neue Response + * @return ResponseInterface das neue Response-Objekt */ - public function __invoke(Request $request, Response $response, $next) + public function __invoke(Request $request, RequestHandler $handler) { if (\Config::get()->getValue('JSONAPI_DANGEROUS_ROUTES_ALLOWED')) { - return $next($request, $response); + return $handler->handle($request); } + $response = new Response(); return $response->withStatus(503)->write('Service Unavailable.'); } diff --git a/lib/classes/JsonApi/Middlewares/JsonApi.php b/lib/classes/JsonApi/Middlewares/JsonApi.php deleted file mode 100644 index cfc9024311f6ca1bffa121a9a1f67e5ef3c17e18..0000000000000000000000000000000000000000 --- a/lib/classes/JsonApi/Middlewares/JsonApi.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php - -namespace JsonApi\Middlewares; - -use JsonApi\Errors\JsonApiExceptionHandler; -use JsonApi\Providers\JsonApiConfig as JsonApiConfigProvider; -use JsonApi\Providers\JsonApiServices as JsonApiServiceProvider; -use Psr\Http\Message\ServerRequestInterface as Request; -use Psr\Http\Message\ResponseInterface as Response; - -/** - * Diese Middleware sorgt dafür, dass alle von ihr versorgten - * (JSON-API-)Routen auf die entsprechend benötigten JSON-API-Services - * zugreifen können. Außerdem sorgt sie dafür, dass ein - * JSON-API-spezifischer Exception-Handler registriert wird. - */ -class JsonApi -{ - /** - * Der Konstruktor. - * - * @param \Slim\App $app die Slim-Applikation - */ - public function __construct($app) - { - $this->app = $app; - } - - /** - * Hier wird der Dependency Container mit JSON-API-spezifischen - * Services befüllt und ein JSON-API-spezifischer - * Exception-Handler registriert. - * - * @param \Psr\Http\Message\ServerRequestInterface $request das - * PSR-7 Request-Objekt - * @param \Psr\Http\Message\ResponseInterface $response das PSR-7 - * Response-Objekt - * @param callable $next das nächste Middleware-Callable - * - * @return \Psr\Http\Message\ResponseInterface die neue Response - */ - public function __invoke(Request $request, Response $response, $next) - { - $container = $this->app->getContainer(); - - $container->register(new JsonApiConfigProvider()); - $container->register(new JsonApiServiceProvider()); - - $this->registerExceptionHandler($container); - - // TODO: wie kriegt man das hier korrekt hin? - $request->registerMediaTypeParser( - 'application/vnd.api+json', - function ($input) { - return json_decode($input, true); - } - ); - - $response = $next($request, $response); - - return $response; - } - - /** - * Register exception handler. - */ - private function registerExceptionHandler($container) - { - $previousHandler = null; - if ($container['errorHandler']) { - $previousHandler = $container['errorHandler']; - } - - unset($container['errorHandler']); - - $container['errorHandler'] = function ($container) use ($previousHandler) { - return new JsonApiExceptionHandler($container, $previousHandler); - }; - } -} diff --git a/lib/classes/JsonApi/Middlewares/RemoveTrailingSlashes.php b/lib/classes/JsonApi/Middlewares/RemoveTrailingSlashes.php index fb3d24ab008cfc0b60fd56aa45ef14bc3bd38d84..3a16702f2ab26e2ac534de80ccada198b184eb06 100644 --- a/lib/classes/JsonApi/Middlewares/RemoveTrailingSlashes.php +++ b/lib/classes/JsonApi/Middlewares/RemoveTrailingSlashes.php @@ -2,8 +2,10 @@ namespace JsonApi\Middlewares; +use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface as Request; -use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Server\RequestHandlerInterface as RequestHandler; +use Slim\Psr7\Response; /** * Diese Klasse definiert eine Middleware, die Requests umleitet, @@ -18,26 +20,35 @@ class RemoveTrailingSlashes * delegiert, sondern eine Response mit `Location`-Header also * einem Redirect zurückgegeben. * - * @param \Psr\Http\Message\ServerRequestInterface $request das - * PSR-7 Request-Objekt - * @param \Psr\Http\Message\ResponseInterface $response das PSR-7 - * Response-Objekt - * @param callable $next das nächste Middleware-Callable + * @param Request $request das Request-Objekt + * @param RequestHandler $handler der PSR-15 Request Handler * - * @return \Psr\Http\Message\ResponseInterface die neue Response + * @return ResponseInterface das neue Response-Objekt */ - public function __invoke(Request $request, Response $response, $next) + public function __invoke(Request $request, RequestHandler $handler) { $uri = $request->getUri(); $path = $uri->getPath(); - if ($path != '/' && substr($path, -1) == '/') { + + if ('/' != $path && '/' == substr($path, -1)) { + // recursively remove slashes when its more than 1 slash + $path = rtrim($path, '/'); + // permanently redirect paths with a trailing slash // to their non-trailing counterpart - $uri = $uri->withPath(substr($path, 0, -1)); + $uri = $uri->withPath($path); + + if ('GET' == $request->getMethod()) { + $response = new Response(); - return $response->withRedirect((string) $uri, 301); + return $response + ->withHeader('Location', (string) $uri) + ->withStatus(301); + } else { + $request = $request->withUri($uri); + } } - return $next($request, $response); + return $handler->handle($request); } } diff --git a/lib/classes/JsonApi/Middlewares/StudipMockNavigation.php b/lib/classes/JsonApi/Middlewares/StudipMockNavigation.php index 72911ea90041b7c2e1818c9a9f24edbea2d8daa5..0bce8a41fd8226a5111f7da99b6a6e78c057e683 100644 --- a/lib/classes/JsonApi/Middlewares/StudipMockNavigation.php +++ b/lib/classes/JsonApi/Middlewares/StudipMockNavigation.php @@ -2,8 +2,9 @@ namespace JsonApi\Middlewares; +use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface as Request; -use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Server\RequestHandlerInterface as RequestHandler; class DummyNavigation extends \Navigation implements \ArrayAccess { @@ -56,10 +57,16 @@ class DummyNavigation extends \Navigation implements \ArrayAccess class StudipMockNavigation { - public function __invoke(Request $request, Response $response, $next) + /** + * @param Request $request das PSR-7 Request-Objekt + * @param RequestHandlerInterface $handler das PSR-7 Response-Objekt + * + * @return ResponseInterface die neue Response + */ + public function __invoke(Request $request, RequestHandler $handler) { \Navigation::setRootNavigation(new DummyNavigation('stuff')); - return $next($request, $response); + return $handler->handle($request); } } diff --git a/lib/classes/JsonApi/Models/Studip.php b/lib/classes/JsonApi/Models/Studip.php index 7e28263d06d9c656b6297cecd5ac05b56a5c737e..ce5fa1cfb9f44f0a17037fcf5e8b8b4ed9612296 100644 --- a/lib/classes/JsonApi/Models/Studip.php +++ b/lib/classes/JsonApi/Models/Studip.php @@ -4,13 +4,6 @@ namespace JsonApi\Models; class Studip { - private $container; - - public function __construct($container) - { - $this->container = $container; - } - public function getId() { return 'studip'; diff --git a/lib/classes/JsonApi/NonJsonApiController.php b/lib/classes/JsonApi/NonJsonApiController.php index cf91ec5a4bfdf98c16eaf6d86f71b918e560b758..8384b54fdd10e41df5a5be93b67fe86096d092e4 100644 --- a/lib/classes/JsonApi/NonJsonApiController.php +++ b/lib/classes/JsonApi/NonJsonApiController.php @@ -4,7 +4,8 @@ namespace JsonApi; use JsonApi\Errors\InternalServerError; use JsonApi\Middlewares\Authentication; -use Neomerx\JsonApi\Contracts\Schema\ContainerInterface as SchemaContainerInterface; +use Neomerx\JsonApi\Contracts\Schema\SchemaContainerInterface; +use Neomerx\JsonApi\Contracts\Schema\SchemaInterface; use Neomerx\JsonApi\Exceptions\JsonApiException; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface as Response; @@ -15,38 +16,55 @@ use Psr\Http\Message\ServerRequestInterface as Request; */ class NonJsonApiController { + /** @var \Psr\Container\ContainerInterface */ + protected $container; + public function __construct(ContainerInterface $container) { $this->container = $container; } - public function __invoke(Request $request, Response $response, $args) + /** + * @return \Psr\Http\Message\ResponseInterface + */ + public function __invoke(Request $request, Response $response, array $args) { try { $response = $this->invoke($request, $response, $args); } catch (JsonApiException $exception) { $httpCode = $exception->getHttpCode(); $errors = $exception->getErrors(); - $reason = count($errors) ? $errors[0]->getId() : ''; + $reason = count($errors) ? $errors[0]->getTitle() ?? '' : ''; - $response = $response->withStatus($httpCode)->write($reason); + $response->getBody()->write($reason); + $response = $response->withStatus($httpCode); } return $response; } - public function invoke(Request $request, Response $response, $args) + public function invoke(Request $request, Response $response, array $args): Response { throw new InternalServerError(); } - protected function getUser($request) + /** + * @return mixed + */ + protected function getUser(Request $request) { return $request->getAttribute(Authentication::USER_KEY, null); } - protected function getSchema($resource) + /** + * Gibt das Schema zu einer beliebigen Ressource zurück. + * + * @param mixed $resource die Ressource, zu der das Schema geliefert werden soll + * + * @return SchemaInterface das Schema zur Ressource + */ + protected function getSchema($resource): SchemaInterface { - return $this->container[SchemaContainerInterface::class]->getSchema($resource); + return $this->container->get(SchemaContainerInterface::class)->getSchema($resource); } } diff --git a/lib/classes/JsonApi/Providers/JsonApiConfig.php b/lib/classes/JsonApi/Providers/JsonApiConfig.php deleted file mode 100644 index 3a8e93a45fe573c65b655aa32a0d5eaf7d1a9c12..0000000000000000000000000000000000000000 --- a/lib/classes/JsonApi/Providers/JsonApiConfig.php +++ /dev/null @@ -1,31 +0,0 @@ -<?php - -namespace JsonApi\Providers; - -/** - * Diese Klasse konfiguriert die JSON-API in der Slim-Applikation um - * die Zuordnung von Schemata zu Stud.IP-Model-Klassen und setzt das - * URL-Prefix für die interne Generierung von URIs. - */ -class JsonApiConfig implements \Pimple\ServiceProviderInterface -{ - /** Config key for schema list */ - const SCHEMAS = 'json-api-integration-schemas'; - - /** Config key for URL prefix that will be added to all document links which have $treatAsHref flag set to false */ - const JSON_URL_PREFIX = 'json-api-integration-urlPrefix'; - - /** - * Diese Methode wird automatisch aufgerufen, wenn diese Klasse dem - * Dependency Container der Slim-Applikation hinzugefügt wird. - * - * Hier werden die Schema-Abbildungen und das JSON-API-URL-Präfix gesetzt. - * - * @param \Pimple\Container $container der Dependency Container - */ - public function register(\Pimple\Container $container) - { - $container[self::SCHEMAS] = new \JsonApi\SchemaMap(); - $container[self::JSON_URL_PREFIX] = rtrim(\URLHelper::getUrl('jsonapi.php/v1'), '/'); - } -} diff --git a/lib/classes/JsonApi/Providers/JsonApiServices.php b/lib/classes/JsonApi/Providers/JsonApiServices.php deleted file mode 100644 index 15b9eedb924af4c819424076a1e61d3a44e96728..0000000000000000000000000000000000000000 --- a/lib/classes/JsonApi/Providers/JsonApiServices.php +++ /dev/null @@ -1,169 +0,0 @@ -<?php - -namespace JsonApi\Providers; - -use JsonApi\Contracts\JsonApiPlugin; -use JsonApi\JsonApiIntegration\Factory; -use JsonApi\JsonApiIntegration\Responses; -use JsonApi\Providers\JsonApiConfig as C; -use Neomerx\JsonApi\Contracts\Codec\CodecMatcherInterface; -use Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface; -use Neomerx\JsonApi\Contracts\Factories\FactoryInterface; -use Neomerx\JsonApi\Contracts\Http\Headers\HeaderParametersInterface; -use Neomerx\JsonApi\Contracts\Http\Headers\HeadersCheckerInterface; -use Neomerx\JsonApi\Contracts\Http\Headers\MediaTypeInterface; -use Neomerx\JsonApi\Contracts\Http\ResponsesInterface; -use Neomerx\JsonApi\Contracts\Schema\ContainerInterface; -use Neomerx\JsonApi\Encoder\EncoderOptions; -use Neomerx\JsonApi\Http\Headers\MediaType; -use Neomerx\JsonApi\Http\Headers\SupportedExtensions; -use Neomerx\JsonApi\Decoders\ArrayDecoder; - -class JsonApiServices implements \Pimple\ServiceProviderInterface -{ - /** - * @SuppressWarnings(PHPMD.ShortVariable) - */ - public function register(\Pimple\Container $container) - { - // register factory - $container[FactoryInterface::class] = function ($c) { - $factory = new Factory(); - - $factory->setDependencyInjectionContainer(new \Pimple\Psr11\Container($c)); - - if ($c->has('logger')) { - $factory->setLogger($c['logger']); - } - - return $factory; - }; - - // register schemas - $container[ContainerInterface::class] = function ($c) { - $schemas = isset($c[C::SCHEMAS]) ? $c[C::SCHEMAS] : []; - $schemaContainer = $c[FactoryInterface::class]->createContainer($schemas); - - $pluginSchemas = \PluginEngine::sendMessage(JsonApiPlugin::class, 'registerSchemas', $schemaContainer); - if (is_array($pluginSchemas) && count($pluginSchemas)) { - foreach ($pluginSchemas as $arrayOfSchemas) { - $schemaContainer->registerArray($arrayOfSchemas); - } - } - - return $schemaContainer; - }; - - // register codec matcher - $container[CodecMatcherInterface::class] = function ($c) { - return $this->createCodecMatcher($c); - }; - - // TODO wo wird das gebraucht - $container[HeadersCheckerInterface::class] = function ($c) { - return $c[FactoryInterface::class]->createHeadersChecker($c[CodecMatcherInterface::class]); - }; - - // register query params - $container[EncodingParametersInterface::class] = function ($c) { - return $c[FactoryInterface::class]->createQueryParametersParser()->parse($c['request']); - }; - - $container[HeaderParametersInterface::class] = function ($c) { - return $c[FactoryInterface::class]->createHeaderParametersParser()->parse($c['request']); - }; - - // register responses - $container[ResponsesInterface::class] = function ($c) { - return $this->createResponses($c); - }; - } - - /** - * @param ContainerInterface $container - * - * @return ResponsesInterface - */ - protected function createResponses($container) - { - $codecMatcher = $container[CodecMatcherInterface::class]; - $parameters = $container[EncodingParametersInterface::class]; - $params = $container[HeaderParametersInterface::class]; - - $codecMatcher->matchEncoder($params->getAcceptHeader()); - $encoder = $codecMatcher->getEncoder(); - - $schemaContainer = $container[ContainerInterface::class]; - $urlPrefix = $container[C::JSON_URL_PREFIX]; - - $responses = new Responses( - new MediaType(MediaTypeInterface::JSON_API_TYPE, MediaTypeInterface::JSON_API_SUB_TYPE), - new SupportedExtensions(), - $encoder, - $schemaContainer, - $parameters, - $urlPrefix - ); - - return $responses; - } - - /** - * @param ContainerInterface $schemaContainer - * - * @return CodecMatcherInterface - */ - protected function createCodecMatcher($container) - { - $factory = $container[FactoryInterface::class]; - $schemaContainer = $container[ContainerInterface::class]; - - $encoderOptions = new EncoderOptions(0, $container[C::JSON_URL_PREFIX]); - - $decoderClosure = $this->getDecoderClosure(); - $encoderClosure = $this->getEncoderClosure($factory, $schemaContainer, $encoderOptions); - $codecMatcher = $factory->createCodecMatcher(); - $jsonApiType = $factory->createMediaType( - MediaTypeInterface::JSON_API_TYPE, - MediaTypeInterface::JSON_API_SUB_TYPE - ); - $jsonApiTypeUtf8 = $factory->createMediaType( - MediaTypeInterface::JSON_API_TYPE, - MediaTypeInterface::JSON_API_SUB_TYPE, - ['charset' => 'UTF-8'] - ); - $codecMatcher->registerEncoder($jsonApiType, $encoderClosure); - $codecMatcher->registerDecoder($jsonApiType, $decoderClosure); - $codecMatcher->registerEncoder($jsonApiTypeUtf8, $encoderClosure); - $codecMatcher->registerDecoder($jsonApiTypeUtf8, $decoderClosure); - - return $codecMatcher; - } - - /** - * @return Closure - */ - protected function getDecoderClosure() - { - return function () { - return new ArrayDecoder(); - }; - } - - /** - * @param FactoryInterface $factory - * @param ContainerInterface $container - * @param EncoderOptions $encoderOptions - * - * @return Closure - */ - private function getEncoderClosure( - FactoryInterface $factory, - ContainerInterface $container, - EncoderOptions $encoderOptions - ) { - return function () use ($factory, $container, $encoderOptions) { - return $factory->createEncoder($container, $encoderOptions); - }; - } -} diff --git a/lib/classes/JsonApi/Providers/StudipConfig.php b/lib/classes/JsonApi/Providers/StudipConfig.php deleted file mode 100644 index 99b3f7ece77a4d8a13c101fc1957b1932089fdf8..0000000000000000000000000000000000000000 --- a/lib/classes/JsonApi/Providers/StudipConfig.php +++ /dev/null @@ -1,36 +0,0 @@ -<?php - -namespace JsonApi\Providers; - -/** - * Diese Klasse konfiguriert die JSON-API in der Slim-Applikation um - * die Zuordnung von Schemata zu Stud.IP-Model-Klassen und setzt das - * URL-Prefix für die interne Generierung von URIs. - */ -class StudipConfig implements \Pimple\ServiceProviderInterface -{ - /** - * Diese Methode wird automatisch aufgerufen, wenn diese Klasse dem - * Dependency Container der Slim-Applikation hinzugefügt wird. - * - * Hier werden die Schema-Abbildungen und das JSON-API-URL-Präfix gesetzt. - * - * @param \Pimple\Container $container der Dependency Container - * - * @SuppressWarnings(PHPMD.Superglobals) - */ - public function register(\Pimple\Container $container) - { - $container['studip-system-object'] = function () { - return new \JsonApi\Models\Studip($container); - }; - - $container['studip-current-user'] = function () { - if ($user = $GLOBALS['user']) { - return $user->getAuthenticatedUser(); - } - - return null; - }; - } -} diff --git a/lib/classes/JsonApi/Providers/StudipServices.php b/lib/classes/JsonApi/Providers/StudipServices.php deleted file mode 100644 index 57def54b17bb02900263481b98e96247d19a7dad..0000000000000000000000000000000000000000 --- a/lib/classes/JsonApi/Providers/StudipServices.php +++ /dev/null @@ -1,41 +0,0 @@ -<?php - -namespace JsonApi\Providers; - -use StudipAuthAbstract; -use User; - -/** - * Diese Klasse stellt Stud.IP-Spezifika zum Beispiel für die - * Authentifizierung zur Verfügung. - */ -class StudipServices implements \Pimple\ServiceProviderInterface -{ - /** - * Schlüssel für den Stud.IP-Authentifizierungservice. - */ - const AUTHENTICATOR = 'studip-authenticator'; - - /** - * Diese Methode wird automatisch aufgerufen, wenn diese Klasse dem - * Dependency Container der Slim-Applikation hinzugefügt wird. - * - * Hier werden die Stud.IP-Spezifika gesetzt - * - * @param \Pimple\Container $container der Dependency Container - */ - public function register(\Pimple\Container $container) - { - $container[self::AUTHENTICATOR] = function ($c) { - return function ($username, $password) { - $check = StudipAuthAbstract::CheckAuthentication($username, $password); - - if ($check['uid'] && $check['uid'] != 'nobody') { - return User::find($check['uid']); - } - - return null; - }; - }; - } -} diff --git a/lib/classes/JsonApi/RouteMap.php b/lib/classes/JsonApi/RouteMap.php index b91c6983bb3aa6d2bed0e5df35baf3a9fa7d3257..a258b10457d3377a891dbbbdad3f77179ab555af 100644 --- a/lib/classes/JsonApi/RouteMap.php +++ b/lib/classes/JsonApi/RouteMap.php @@ -7,7 +7,7 @@ use JsonApi\Middlewares\Authentication; use JsonApi\Middlewares\DangerousRouteHandler; use JsonApi\Middlewares\JsonApi as JsonApiMiddleware; use JsonApi\Middlewares\StudipMockNavigation; -use JsonApi\Providers\StudipServices; +use Slim\Routing\RouteCollectorProxy; /** * Diese Klasse ist die JSON-API-Routemap, in der alle Routen @@ -48,7 +48,6 @@ use JsonApi\Providers\StudipServices; * * $this->app->post('/article/{id}/comments', MeineRoute::class); * - * * @see \JsonApi\Middlewares\JsonApi * @see \JsonApi\Middlewares\Authentication * @see \JsonApi\Contracts\JsonApiPlugin @@ -58,6 +57,9 @@ use JsonApi\Providers\StudipServices; */ class RouteMap { + /** @var \Slim\App */ + private $app; + /** * Der Konstruktor. * @@ -76,40 +78,12 @@ class RouteMap * RouteMap::authenticatedRoutes eingetragen. Routen ohne * Autorisierung werden in RouteMap::unauthenticatedRoutes vermerkt. */ - public function __invoke() + public function __invoke(RouteCollectorProxy $group): void { - $corsOrigin = \Config::get()->getValue('JSONAPI_CORS_ORIGIN'); - if (is_array($corsOrigin) && count($corsOrigin)) { - $this->app->add( - new \Tuupola\Middleware\Cors( - [ - 'origin' => $corsOrigin, - 'methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], - 'headers.allow' => [ - 'Accept', - 'Accept-Encoding', - 'Accept-Language', - 'Authorization', - 'Content-Type', - 'Origin', - ], - 'headers.expose' => ['Etag'], - 'credentials' => true, - 'cache' => 86400, - ] - ) - ); - } - - $this->app->add(new JsonApiMiddleware($this->app)); - - $this->app->add(new StudipMockNavigation()); - - $this->app->group('', [$this, 'authenticatedRoutes']) - ->add(new Authentication($this->getAuthenticator())); - $this->app->group('', [$this, 'unauthenticatedRoutes']); - - $this->app->get('/discovery', Routes\DiscoveryIndex::class); + $group->group('', [$this, 'authenticatedRoutes'])->add(new Authentication($this->getAuthenticator())); + $group->group('', [$this, 'unauthenticatedRoutes']); + + $group->get('/discovery', Routes\DiscoveryIndex::class); } /** @@ -117,44 +91,43 @@ class RouteMap * Außerdem wird über die \PluginEngine allen JsonApiPlugins die * Möglichkeit gegeben, sich hier einzutragen. */ - public function authenticatedRoutes() + public function authenticatedRoutes(RouteCollectorProxy $group): void { \PluginEngine::sendMessage(JsonApiPlugin::class, 'registerAuthenticatedRoutes', $this->app); - $this->app->get('/users', Routes\Users\UsersIndex::class); - $this->app->get('/users/me', Routes\Users\UsersShow::class); - $this->app->get('/users/{id}', Routes\Users\UsersShow::class); - $this->app->delete('/users/{id}', Routes\Users\UsersDelete::class)->add(DangerousRouteHandler::class); - - $this->app->get('/users/{id}/activitystream', Routes\ActivityStreamShow::class); - $this->app->get('/users/{id}/institute-memberships', Routes\InstituteMemberships\ByUserIndex::class); - $this->app->get('/users/{id}/course-memberships', Routes\CourseMemberships\ByUserIndex::class); - $this->app->get('/course-memberships/{id}', Routes\CourseMemberships\CourseMembershipsShow::class); - $this->app->patch('/course-memberships/{id}', Routes\CourseMemberships\CourseMembershipsUpdate::class); - - $this->app->get('/users/{id}/schedule', Routes\Schedule\UserScheduleShow::class)->setName('get-schedule'); - $this->app->get('/schedule-entries/{id}', Routes\Schedule\ScheduleEntriesShow::class); - $this->app->get('/seminar-cycle-dates/{id}', Routes\Schedule\SeminarCycleDatesShow::class); - - $this->app->get('/users/{id}/config-values', Routes\ConfigValues\ByUserIndex::class); - $this->app->get('/config-values/{id}', Routes\ConfigValues\ConfigValuesShow::class); - $this->app->patch('/config-values/{id}', Routes\ConfigValues\ConfigValuesUpdate::class); - - - $this->addAuthenticatedBlubberRoutes(); -// $this->addAuthenticatedConsultationRoutes(); - $this->addAuthenticatedContactsRoutes(); - $this->addAuthenticatedCoursesRoutes(); - $this->addAuthenticatedCoursewareRoutes(); - $this->addAuthenticatedEventsRoutes(); - $this->addAuthenticatedFeedbackRoutes(); - $this->addAuthenticatedFilesRoutes(); - $this->addAuthenticatedForumRoutes(); - $this->addAuthenticatedInstitutesRoutes(); - $this->addAuthenticatedMessagesRoutes(); - $this->addAuthenticatedNewsRoutes(); - $this->addAuthenticatedStudyAreasRoutes(); - $this->addAuthenticatedWikiRoutes(); + $group->get('/users', Routes\Users\UsersIndex::class); + $group->get('/users/me', Routes\Users\UsersShow::class)->setName('get-myself'); + $group->get('/users/{id}', Routes\Users\UsersShow::class); + $group->delete('/users/{id}', Routes\Users\UsersDelete::class)->add(DangerousRouteHandler::class); + + $group->get('/users/{id}/activitystream', Routes\ActivityStreamShow::class); + $group->get('/users/{id}/institute-memberships', Routes\InstituteMemberships\ByUserIndex::class); + $group->get('/users/{id}/course-memberships', Routes\CourseMemberships\ByUserIndex::class); + $group->get('/course-memberships/{id}', Routes\CourseMemberships\CourseMembershipsShow::class); + $group->patch('/course-memberships/{id}', Routes\CourseMemberships\CourseMembershipsUpdate::class); + + $group->get('/users/{id}/schedule', Routes\Schedule\UserScheduleShow::class)->setName('get-schedule'); + $group->get('/schedule-entries/{id}', Routes\Schedule\ScheduleEntriesShow::class); + $group->get('/seminar-cycle-dates/{id}', Routes\Schedule\SeminarCycleDatesShow::class); + + $group->get('/users/{id}/config-values', Routes\ConfigValues\ByUserIndex::class); + $group->get('/config-values/{id}', Routes\ConfigValues\ConfigValuesShow::class); + $group->patch('/config-values/{id}', Routes\ConfigValues\ConfigValuesUpdate::class); + + $this->addAuthenticatedBlubberRoutes($group); + // $this->addAuthenticatedConsultationRoutes($group); + $this->addAuthenticatedContactsRoutes($group); + $this->addAuthenticatedCoursesRoutes($group); + $this->addAuthenticatedCoursewareRoutes($group); + $this->addAuthenticatedEventsRoutes($group); + $this->addAuthenticatedFeedbackRoutes($group); + $this->addAuthenticatedFilesRoutes($group); + $this->addAuthenticatedForumRoutes($group); + $this->addAuthenticatedInstitutesRoutes($group); + $this->addAuthenticatedMessagesRoutes($group); + $this->addAuthenticatedNewsRoutes($group); + $this->addAuthenticatedStudyAreasRoutes($group); + $this->addAuthenticatedWikiRoutes($group); } /** @@ -162,341 +135,357 @@ class RouteMap * Außerdem wird über die \PluginEngine allen JsonApiPlugins die * Möglichkeit gegeben, sich hier einzutragen. */ - public function unauthenticatedRoutes() + public function unauthenticatedRoutes(RouteCollectorProxy $group): void { - \PluginEngine::sendMessage(JsonApiPlugin::class, 'registerUnauthenticatedRoutes', $this->app); + \PluginEngine::sendMessage(JsonApiPlugin::class, 'registerUnauthenticatedRoutes', $group); - $this->app->get('/semesters', Routes\SemestersIndex::class); - $this->app->get('/semesters/{id}', Routes\SemestersShow::class); + $group->get('/semesters', Routes\SemestersIndex::class); + $group->get('/semesters/{id}', Routes\SemestersShow::class)->setName('get-semester'); - $this->app->get('/studip/properties', Routes\Studip\PropertiesIndex::class); + $group->get('/studip/properties', Routes\Studip\PropertiesIndex::class); } - private function getAuthenticator() + private function getAuthenticator(): callable { - $container = $this->app->getContainer(); - - return $container[StudipServices::AUTHENTICATOR]; + return $this->app->getContainer()->get('studip-authenticator'); } - private function addAuthenticatedBlubberRoutes() + private function addAuthenticatedBlubberRoutes(RouteCollectorProxy $group): void { // find BlubberThreads - $this->app->get('/courses/{id}/blubber-threads', Routes\Blubber\ThreadsIndex::class) - ->setArgument('type', 'course'); - $this->app->get('/institutes/{id}/blubber-threads', Routes\Blubber\ThreadsIndex::class) - ->setArgument('type', 'institute'); - $this->app->get('/studip/blubber-threads', Routes\Blubber\ThreadsIndex::class) - ->setArgument('type', 'public'); - $this->app->get('/users/{id}/blubber-threads', Routes\Blubber\ThreadsIndex::class) - ->setArgument('type', 'private'); - $this->app->get('/blubber-threads', Routes\Blubber\ThreadsIndex::class) - ->setArgument('type', 'all'); - $this->app->get('/blubber-threads/{id}', Routes\Blubber\ThreadsShow::class); + $group->get('/courses/{id}/blubber-threads', Routes\Blubber\ThreadsIndex::class)->setArgument('type', 'course'); + $group + ->get('/institutes/{id}/blubber-threads', Routes\Blubber\ThreadsIndex::class) + ->setArgument('type', 'institute'); + $group->get('/studip/blubber-threads', Routes\Blubber\ThreadsIndex::class)->setArgument('type', 'public'); + $group->get('/users/{id}/blubber-threads', Routes\Blubber\ThreadsIndex::class)->setArgument('type', 'private'); + $group->get('/blubber-threads', Routes\Blubber\ThreadsIndex::class)->setArgument('type', 'all'); + $group->get('/blubber-threads/{id}', Routes\Blubber\ThreadsShow::class); // create, read, update and delete BlubberComments - $this->app->get('/blubber-threads/{id}/comments', Routes\Blubber\CommentsByThreadIndex::class); - $this->app->post('/blubber-threads/{id}/comments', Routes\Blubber\CommentsCreate::class); - $this->app->get('/blubber-comments', Routes\Blubber\CommentsIndex::class); - $this->app->get('/blubber-comments/{id}', Routes\Blubber\CommentsShow::class); - $this->app->patch('/blubber-comments/{id}', Routes\Blubber\CommentsUpdate::class); - $this->app->delete('/blubber-comments/{id}', Routes\Blubber\CommentsDelete::class); + $group->get('/blubber-threads/{id}/comments', Routes\Blubber\CommentsByThreadIndex::class); + $group->post('/blubber-threads/{id}/comments', Routes\Blubber\CommentsCreate::class); + $group->get('/blubber-comments', Routes\Blubber\CommentsIndex::class); + $group->get('/blubber-comments/{id}', Routes\Blubber\CommentsShow::class); + $group->patch('/blubber-comments/{id}', Routes\Blubber\CommentsUpdate::class); + $group->delete('/blubber-comments/{id}', Routes\Blubber\CommentsDelete::class); // REL mentions - $this->addRelationship('/blubber-threads/{id}/relationships/mentions', Routes\Blubber\Rel\Mentions::class); + $this->addRelationship( + $group, + '/blubber-threads/{id}/relationships/mentions', + Routes\Blubber\Rel\Mentions::class + ); } - private function addAuthenticatedConsultationRoutes() + private function addAuthenticatedConsultationRoutes(RouteCollectorProxy $group): void { - $this->app->get('/users/{id}/consultations', Routes\Consultations\BlocksByUserIndex::class); - - $this->app->get('/consultation-blocks/{id}', Routes\Consultations\BlockShow::class); - $this->app->get('/consultation-blocks/{id}/slots', Routes\Consultations\SlotsByBlockIndex::class); + $group->get('/users/{id}/consultations', Routes\Consultations\BlocksByUserIndex::class); - $this->app->get('/consultation-slots/{id}', Routes\Consultations\SlotShow::class); - $this->app->get('/consultation-slots/{id}/bookings', Routes\Consultations\BookingsBySlotIndex::class); - $this->app->post('/consultation-slots/{id}/bookings', Routes\Consultations\BookingsCreate::class); + $group->get('/consultation-blocks/{id}', Routes\Consultations\BlockShow::class); + $group->get('/consultation-blocks/{id}/slots', Routes\Consultations\SlotsByBlockIndex::class); - $this->app->get('/consultation-bookings/{id}', Routes\Consultations\BookingsShow::class); - $this->app->delete('/consultation-bookings/{id}', Routes\Consultations\BookingsDelete::class); + $group->get('/consultation-slots/{id}', Routes\Consultations\SlotShow::class); + $group->get('/consultation-slots/{id}/bookings', Routes\Consultations\BookingsBySlotIndex::class); + $group->post('/consultation-slots/{id}/bookings', Routes\Consultations\BookingsCreate::class); -// $this->addRelationship('/users/{id}/relationships/contacts', Routes\Users\Rel\Contacts::class); + $group->get('/consultation-bookings/{id}', Routes\Consultations\BookingsShow::class); + $group->delete('/consultation-bookings/{id}', Routes\Consultations\BookingsDelete::class); } - private function addAuthenticatedContactsRoutes() + private function addAuthenticatedContactsRoutes(RouteCollectorProxy $group): void { - $this->app->get('/users/{id}/contacts', Routes\Users\ContactsIndex::class); - $this->addRelationship('/users/{id}/relationships/contacts', Routes\Users\Rel\Contacts::class); + $group->get('/users/{id}/contacts', Routes\Users\ContactsIndex::class); + $this->addRelationship($group, '/users/{id}/relationships/contacts', Routes\Users\Rel\Contacts::class); } - private function addAuthenticatedEventsRoutes() + private function addAuthenticatedEventsRoutes(RouteCollectorProxy $group): void { - $this->app->get('/courses/{id}/events', Routes\Events\CourseEventsIndex::class); - $this->app->get('/users/{id}/events', Routes\Events\UserEventsIndex::class); + $group->get('/courses/{id}/events', Routes\Events\CourseEventsIndex::class); + $group->get('/users/{id}/events', Routes\Events\UserEventsIndex::class); // not a JSON:API route - $this->app->get('/users/{id}/events.ics', Routes\Events\UserEventsIcal::class); + $group->get('/users/{id}/events.ics', Routes\Events\UserEventsIcal::class); } - private function addAuthenticatedFeedbackRoutes() + private function addAuthenticatedFeedbackRoutes(RouteCollectorProxy $group): void { - $this->app->get('/feedback-elements/{id}', Routes\Feedback\FeedbackElementsShow::class); - $this->app->get('/feedback-elements/{id}/entries', Routes\Feedback\FeedbackEntriesIndex::class); - $this->app->get('/courses/{id}/feedback-elements', Routes\Feedback\FeedbackElementsByCourseIndex::class); - $this->app->get('/file-refs/{id}/feedback-elements', Routes\Feedback\FeedbackElementsByFileRefIndex::class); - $this->app->get('/folders/{id}/feedback-elements', Routes\Feedback\FeedbackElementsByFolderIndex::class); + $group->get('/feedback-elements/{id}', Routes\Feedback\FeedbackElementsShow::class); + $group->get('/feedback-elements/{id}/entries', Routes\Feedback\FeedbackEntriesIndex::class); + $group->get('/courses/{id}/feedback-elements', Routes\Feedback\FeedbackElementsByCourseIndex::class); + $group->get('/file-refs/{id}/feedback-elements', Routes\Feedback\FeedbackElementsByFileRefIndex::class); + $group->get('/folders/{id}/feedback-elements', Routes\Feedback\FeedbackElementsByFolderIndex::class); - $this->app->get('/feedback-entries/{id}', Routes\Feedback\FeedbackEntriesShow::class); + $group->get('/feedback-entries/{id}', Routes\Feedback\FeedbackEntriesShow::class); } - private function addAuthenticatedInstitutesRoutes() + private function addAuthenticatedInstitutesRoutes(RouteCollectorProxy $group): void { - $this->app->get('/institute-memberships/{id}', Routes\InstituteMemberships\InstituteMembershipsShow::class); - $this->app->get('/institutes/{id}', Routes\Institutes\InstitutesShow::class); - $this->app->get('/institutes', Routes\Institutes\InstitutesIndex::class); + $group->get('/institute-memberships/{id}', Routes\InstituteMemberships\InstituteMembershipsShow::class); + $group->get('/institutes/{id}', Routes\Institutes\InstitutesShow::class); + $group->get('/institutes', Routes\Institutes\InstitutesIndex::class); - $this->app->get('/institutes/{id}/status-groups', Routes\Institutes\StatusGroupsOfInstitutes::class); + $group->get('/institutes/{id}/status-groups', Routes\Institutes\StatusGroupsOfInstitutes::class); } - private function addAuthenticatedNewsRoutes() + private function addAuthenticatedNewsRoutes(RouteCollectorProxy $group): void { - $this->app->post('/courses/{id}/news', Routes\News\CourseNewsCreate::class); - $this->app->post('/users/{id}/news', Routes\News\UserNewsCreate::class); - $this->app->post('/news', Routes\News\StudipNewsCreate::class); - $this->app->post('/news/{id}/comments', Routes\News\CommentCreate::class); - $this->app->patch('/news/{id}', Routes\News\NewsUpdate::class); - $this->app->get('/news/{id}', Routes\News\NewsShow::class); - $this->app->get('/courses/{id}/news', Routes\News\ByCourseIndex::class); - $this->app->get('/users/{id}/news', Routes\News\ByUserIndex::class); - $this->app->get('/news/{id}/comments', Routes\News\CommentsIndex::class); - $this->app->get('/news', Routes\News\ByCurrentUser::class); - $this->app->get('/studip/news', Routes\News\GlobalNewsShow::class); - $this->app->delete('/news/{id}', Routes\News\NewsDelete::class); - $this->app->delete('/comments/{id}', Routes\News\CommentsDelete::class); + $group->post('/courses/{id}/news', Routes\News\CourseNewsCreate::class); + $group->post('/users/{id}/news', Routes\News\UserNewsCreate::class); + $group->post('/news', Routes\News\StudipNewsCreate::class); + $group->post('/news/{id}/comments', Routes\News\CommentCreate::class); + $group->patch('/news/{id}', Routes\News\NewsUpdate::class); + $group->get('/news/{id}', Routes\News\NewsShow::class); + $group->get('/courses/{id}/news', Routes\News\ByCourseIndex::class); + $group->get('/users/{id}/news', Routes\News\ByUserIndex::class); + $group->get('/news/{id}/comments', Routes\News\CommentsIndex::class); + $group->get('/news', Routes\News\ByCurrentUser::class); + $group->get('/studip/news', Routes\News\GlobalNewsShow::class); + $group->delete('/news/{id}', Routes\News\NewsDelete::class); + $group->delete('/comments/{id}', Routes\News\CommentsDelete::class); // RELATIONSHIP: 'ranges' - $this->addRelationship('/news/{id}/relationships/ranges', Routes\News\Rel\Ranges::class); + $this->addRelationship($group, '/news/{id}/relationships/ranges', Routes\News\Rel\Ranges::class); } - private function addAuthenticatedStudyAreasRoutes() + private function addAuthenticatedStudyAreasRoutes(RouteCollectorProxy $group): void { - $this->app->get('/study-areas', Routes\StudyAreas\StudyAreasIndex::class); - $this->app->get('/study-areas/{id}', Routes\StudyAreas\StudyAreasShow::class); + $group->get('/study-areas', Routes\StudyAreas\StudyAreasIndex::class); + $group->get('/study-areas/{id}', Routes\StudyAreas\StudyAreasShow::class); - $this->app->get('/study-areas/{id}/children', Routes\StudyAreas\ChildrenOfStudyAreas::class); - $this->app->get('/study-areas/{id}/courses', Routes\StudyAreas\CoursesOfStudyAreas::class); - $this->app->get('/study-areas/{id}/institute', Routes\StudyAreas\InstituteOfStudyAreas::class); - $this->app->get('/study-areas/{id}/parent', Routes\StudyAreas\ParentOfStudyAreas::class); + $group->get('/study-areas/{id}/children', Routes\StudyAreas\ChildrenOfStudyAreas::class); + $group->get('/study-areas/{id}/courses', Routes\StudyAreas\CoursesOfStudyAreas::class); + $group->get('/study-areas/{id}/institute', Routes\StudyAreas\InstituteOfStudyAreas::class); + $group->get('/study-areas/{id}/parent', Routes\StudyAreas\ParentOfStudyAreas::class); } - private function addAuthenticatedWikiRoutes() + private function addAuthenticatedWikiRoutes(RouteCollectorProxy $group): void { - $this->addRelationship('/wiki-pages/{id:.+}/relationships/parent', Routes\Wiki\Rel\ParentPage::class); - $this->app->get('/wiki-pages/{id:.+}/children', Routes\Wiki\ChildrenIndex::class); - $this->app->get('/wiki-pages/{id:.+}/descendants', Routes\Wiki\DescendantsIndex::class); + $this->addRelationship($group, '/wiki-pages/{id:.+}/relationships/parent', Routes\Wiki\Rel\ParentPage::class); + $group->get('/wiki-pages/{id:.+}/children', Routes\Wiki\ChildrenIndex::class); + $group->get('/wiki-pages/{id:.+}/descendants', Routes\Wiki\DescendantsIndex::class); - $this->app->get('/courses/{id}/wiki-pages', Routes\Wiki\WikiIndex::class); - $this->app->get('/wiki-pages/{id:.+}', Routes\Wiki\WikiShow::class)->setName('get-wiki-page'); + $group->get('/courses/{id}/wiki-pages', Routes\Wiki\WikiIndex::class); + $group->get('/wiki-pages/{id:.+}', Routes\Wiki\WikiShow::class)->setName('get-wiki-page'); - $this->app->post('/courses/{id}/wiki-pages', Routes\Wiki\WikiCreate::class); - $this->app->patch('/wiki-pages/{id:.+}', Routes\Wiki\WikiUpdate::class); - $this->app->delete('/wiki-pages/{id:.+}', Routes\Wiki\WikiDelete::class); + $group->post('/courses/{id}/wiki-pages', Routes\Wiki\WikiCreate::class); + $group->patch('/wiki-pages/{id:.+}', Routes\Wiki\WikiUpdate::class); + $group->delete('/wiki-pages/{id:.+}', Routes\Wiki\WikiDelete::class); } - private function addAuthenticatedCoursesRoutes() + private function addAuthenticatedCoursesRoutes(RouteCollectorProxy $group): void { - $this->app->get('/courses', Routes\Courses\CoursesIndex::class); - $this->app->get('/courses/{id}', Routes\Courses\CoursesShow::class); + $group->get('/courses', Routes\Courses\CoursesIndex::class); + $group->get('/courses/{id}', Routes\Courses\CoursesShow::class); - $this->app->get('/users/{id}/courses', Routes\Courses\CoursesByUserIndex::class); + $group->get('/users/{id}/courses', Routes\Courses\CoursesByUserIndex::class); - $this->app->get('/courses/{id}/memberships', Routes\Courses\CoursesMembershipsIndex::class); - $this->addRelationship('/courses/{id}/relationships/memberships', Routes\Courses\Rel\Memberships::class); + $group->get('/courses/{id}/memberships', Routes\Courses\CoursesMembershipsIndex::class); + $this->addRelationship( + $group, + '/courses/{id}/relationships/memberships', + Routes\Courses\Rel\Memberships::class + ); - $this->app->get('/courses/{id}/status-groups', Routes\Courses\StatusGroupsOfCourses::class); + $group->get('/courses/{id}/status-groups', Routes\Courses\StatusGroupsOfCourses::class); - $this->app->get('/sem-classes', Routes\Courses\SemClassesIndex::class); - $this->app->get('/sem-classes/{id}', Routes\Courses\SemClassesShow::class); - $this->app->get('/sem-classes/{id}/sem-types', Routes\Courses\SemTypesBySemClassIndex::class); - $this->app->get('/sem-types', Routes\Courses\SemTypesIndex::class); - $this->app->get('/sem-types/{id}', Routes\Courses\SemTypesShow::class); + $group->get('/sem-classes', Routes\Courses\SemClassesIndex::class); + $group->get('/sem-classes/{id}', Routes\Courses\SemClassesShow::class); + $group->get('/sem-classes/{id}/sem-types', Routes\Courses\SemTypesBySemClassIndex::class); + $group->get('/sem-types', Routes\Courses\SemTypesIndex::class); + $group->get('/sem-types/{id}', Routes\Courses\SemTypesShow::class); } - private function addAuthenticatedCoursewareRoutes() + private function addAuthenticatedCoursewareRoutes(RouteCollectorProxy $group): void { - $this->app->get('/{type:courses|users}/{id}/courseware', Routes\Courseware\CoursewareInstancesShow::class); - $this->app->patch('/courseware-instances/{id}', Routes\Courseware\CoursewareInstancesUpdate::class); + $group->get('/{type:courses|users}/{id}/courseware', Routes\Courseware\CoursewareInstancesShow::class); + $group->patch('/courseware-instances/{id}', Routes\Courseware\CoursewareInstancesUpdate::class); $this->addRelationship( + $group, '/courseware-instances/{id}/relationships/bookmarks', Routes\Courseware\Rel\BookmarkedStructuralElements::class ); - $this->app->get( - '/courseware-instances/{id}/bookmarks', - Routes\Courseware\BookmarkedStructuralElementsIndex::class - ); + $group->get('/courseware-instances/{id}/bookmarks', Routes\Courseware\BookmarkedStructuralElementsIndex::class); - $this->app->get('/courseware-blocks/{id}', Routes\Courseware\BlocksShow::class); - $this->app->post('/courseware-blocks', Routes\Courseware\BlocksCreate::class); - $this->app->patch('/courseware-blocks/{id}', Routes\Courseware\BlocksUpdate::class); - $this->app->delete('/courseware-blocks/{id}', Routes\Courseware\BlocksDelete::class); + $group->get('/courseware-blocks/{id}', Routes\Courseware\BlocksShow::class); + $group->post('/courseware-blocks', Routes\Courseware\BlocksCreate::class); + $group->patch('/courseware-blocks/{id}', Routes\Courseware\BlocksUpdate::class); + $group->delete('/courseware-blocks/{id}', Routes\Courseware\BlocksDelete::class); $this->addRelationship( + $group, '/courseware-blocks/{id}/relationships/edit-blocker', Routes\Courseware\Rel\BlocksEditBlocker::class ); $this->addRelationship( + $group, '/courseware-blocks/{id}/relationships/file-refs', Routes\Courseware\Rel\BlocksFilerefs::class ); - $this->app->get('/courseware-blocks/{id}/file-refs', Routes\Courseware\BlocksListFiles::class); + $group->get('/courseware-blocks/{id}/file-refs', Routes\Courseware\BlocksListFiles::class); // not a JSON route - $this->app->post('/courseware-blocks/{id}/copy', Routes\Courseware\BlocksCopy::class); + $group->post('/courseware-blocks/{id}/copy', Routes\Courseware\BlocksCopy::class); - $this->app->get('/courseware-containers/{id}', Routes\Courseware\ContainersShow::class); - $this->app->post('/courseware-containers', Routes\Courseware\ContainersCreate::class); - $this->app->patch('/courseware-containers/{id}', Routes\Courseware\ContainersUpdate::class); - $this->app->delete('/courseware-containers/{id}', Routes\Courseware\ContainersDelete::class); - $this->app->get('/courseware-containers/{id}/blocks', Routes\Courseware\BlocksIndex::class); + $group->get('/courseware-containers/{id}', Routes\Courseware\ContainersShow::class); + $group->post('/courseware-containers', Routes\Courseware\ContainersCreate::class); + $group->patch('/courseware-containers/{id}', Routes\Courseware\ContainersUpdate::class); + $group->delete('/courseware-containers/{id}', Routes\Courseware\ContainersDelete::class); + $group->get('/courseware-containers/{id}/blocks', Routes\Courseware\BlocksIndex::class); $this->addRelationship( + $group, '/courseware-containers/{id}/relationships/blocks', Routes\Courseware\Rel\ContainersBlocks::class ); $this->addRelationship( + $group, '/courseware-containers/{id}/relationships/edit-blocker', Routes\Courseware\Rel\ContainersEditBlocker::class ); // not a JSON route - $this->app->post('/courseware-containers/{id}/copy', Routes\Courseware\ContainersCopy::class); + $group->post('/courseware-containers/{id}/copy', Routes\Courseware\ContainersCopy::class); - $this->app->get('/courseware-structural-elements/{id}', Routes\Courseware\StructuralElementsShow::class); - $this->app->get('/courseware-structural-elements', Routes\Courseware\StructuralElementsIndex::class); - $this->app->post('/courseware-structural-elements', Routes\Courseware\StructuralElementsCreate::class); - $this->app->patch('/courseware-structural-elements/{id}', Routes\Courseware\StructuralElementsUpdate::class); - $this->app->delete('/courseware-structural-elements/{id}', Routes\Courseware\StructuralElementsDelete::class); + $group->get('/courseware-structural-elements/{id}', Routes\Courseware\StructuralElementsShow::class); + $group->get('/courseware-structural-elements', Routes\Courseware\StructuralElementsIndex::class); + $group->post('/courseware-structural-elements', Routes\Courseware\StructuralElementsCreate::class); + $group->patch('/courseware-structural-elements/{id}', Routes\Courseware\StructuralElementsUpdate::class); + $group->delete('/courseware-structural-elements/{id}', Routes\Courseware\StructuralElementsDelete::class); - $this->app->get( + $group->get( '/courseware-structural-elements/{id}/children', Routes\Courseware\ChildrenOfStructuralElementsIndex::class ); - $this->app->get('/courseware-structural-elements/{id}/containers', Routes\Courseware\ContainersIndex::class); + $group->get('/courseware-structural-elements/{id}/containers', Routes\Courseware\ContainersIndex::class); $this->addRelationship( + $group, '/courseware-structural-elements/{id}/relationships/containers', Routes\Courseware\Rel\StructuralElementsContainers::class ); $this->addRelationship( + $group, '/courseware-structural-elements/{id}/relationships/children', Routes\Courseware\Rel\StructuralElementsChildren::class ); - $this->app->get( + $group->get( '/courseware-structural-elements/{id}/descendants', Routes\Courseware\DescendantsOfStructuralElementsIndex::class ); $this->addRelationship( + $group, '/courseware-structural-elements/{id}/relationships/edit-blocker', Routes\Courseware\Rel\StructuralElementsEditBlocker::class ); - $this->app->post('/courseware-structural-elements/{id}/image', Routes\Courseware\StructuralElementsImageUpload::class); - $this->app->delete('/courseware-structural-elements/{id}/image', Routes\Courseware\StructuralElementsImageDelete::class); + $group->post( + '/courseware-structural-elements/{id}/image', + Routes\Courseware\StructuralElementsImageUpload::class + ); + $group->delete( + '/courseware-structural-elements/{id}/image', + Routes\Courseware\StructuralElementsImageDelete::class + ); // not a JSON route - $this->app->post('/courseware-structural-elements/{id}/copy', Routes\Courseware\StructuralElementsCopy::class); + $group->post('/courseware-structural-elements/{id}/copy', Routes\Courseware\StructuralElementsCopy::class); - $this->app->get('/courseware-blocks/{id}/user-data-field', Routes\Courseware\UserDataFieldOfBlocksShow::class); - $this->app->get('/courseware-user-data-fields/{id}', Routes\Courseware\UserDataFieldsShow::class); - $this->app->patch('/courseware-user-data-fields/{id}', Routes\Courseware\UserDataFieldsUpdate::class); + $group->get('/courseware-blocks/{id}/user-data-field', Routes\Courseware\UserDataFieldOfBlocksShow::class); + $group->get('/courseware-user-data-fields/{id}', Routes\Courseware\UserDataFieldsShow::class); + $group->patch('/courseware-user-data-fields/{id}', Routes\Courseware\UserDataFieldsUpdate::class); - $this->app->get('/courseware-blocks/{id}/user-progress', Routes\Courseware\UserProgressOfBlocksShow::class); - $this->app->get('/courseware-user-progresses/{id}', Routes\Courseware\UserProgressesShow::class); - $this->app->patch('/courseware-user-progresses/{id}', Routes\Courseware\UserProgressesUpdate::class); + $group->get('/courseware-blocks/{id}/user-progress', Routes\Courseware\UserProgressOfBlocksShow::class); + $group->get('/courseware-user-progresses/{id}', Routes\Courseware\UserProgressesShow::class); + $group->patch('/courseware-user-progresses/{id}', Routes\Courseware\UserProgressesUpdate::class); - $this->app->get('/courseware-blocks/{id}/comments', Routes\Courseware\BlockCommentsOfBlocksIndex::class); - $this->app->post('/courseware-block-comments', Routes\Courseware\BlockCommentsCreate::class); - $this->app->get('/courseware-block-comments/{id}', Routes\Courseware\BlockCommentsShow::class); - $this->app->patch('/courseware-block-comments/{id}', Routes\Courseware\BlockCommentsUpdate::class); - $this->app->delete('/courseware-block-comments/{id}', Routes\Courseware\BlockCommentsDelete::class); + $group->get('/courseware-blocks/{id}/comments', Routes\Courseware\BlockCommentsOfBlocksIndex::class); + $group->post('/courseware-block-comments', Routes\Courseware\BlockCommentsCreate::class); + $group->get('/courseware-block-comments/{id}', Routes\Courseware\BlockCommentsShow::class); + $group->patch('/courseware-block-comments/{id}', Routes\Courseware\BlockCommentsUpdate::class); + $group->delete('/courseware-block-comments/{id}', Routes\Courseware\BlockCommentsDelete::class); - $this->app->get('/courseware-blocks/{id}/feedback', Routes\Courseware\BlockFeedbacksOfBlocksIndex::class); - $this->app->post('/courseware-block-feedback', Routes\Courseware\BlockFeedbacksCreate::class); - $this->app->get('/courseware-block-feedback/{id}', Routes\Courseware\BlockFeedbacksShow::class); + $group->get('/courseware-blocks/{id}/feedback', Routes\Courseware\BlockFeedbacksOfBlocksIndex::class); + $group->post('/courseware-block-feedback', Routes\Courseware\BlockFeedbacksCreate::class); + $group->get('/courseware-block-feedback/{id}', Routes\Courseware\BlockFeedbacksShow::class); } - private function addAuthenticatedFilesRoutes() + private function addAuthenticatedFilesRoutes(RouteCollectorProxy $group): void { - $this->app->get('/terms-of-use', Routes\Files\TermsOfUseIndex::class); - $this->app->get('/terms-of-use/{id}', Routes\Files\TermsOfUseShow::class); + $group->get('/terms-of-use', Routes\Files\TermsOfUseIndex::class); + $group->get('/terms-of-use/{id}', Routes\Files\TermsOfUseShow::class); - $this->app->get('/{type:courses|institutes|users}/{id}/file-refs', Routes\Files\RangeFileRefsIndex::class); - $this->app->get('/{type:courses|institutes|users}/{id}/folders', Routes\Files\RangeFoldersIndex::class); + $group->get('/{type:courses|institutes|users}/{id}/file-refs', Routes\Files\RangeFileRefsIndex::class); + $group->get('/{type:courses|institutes|users}/{id}/folders', Routes\Files\RangeFoldersIndex::class); - $this->app->post('/{type:courses|institutes|users}/{id}/folders', Routes\Files\RangeFoldersCreate::class); + $group->post('/{type:courses|institutes|users}/{id}/folders', Routes\Files\RangeFoldersCreate::class); - $this->app->get('/file-refs/{id}', Routes\Files\FileRefsShow::class); - $this->app->patch('/file-refs/{id}', Routes\Files\FileRefsUpdate::class); - $this->app->delete('/file-refs/{id}', Routes\Files\FileRefsDelete::class); - $this->addRelationship('/file-refs/{id}/relationships/terms-of-use', Routes\Files\Rel\TermsOfFileRef::class); + $group->get('/file-refs/{id}', Routes\Files\FileRefsShow::class); + $group->patch('/file-refs/{id}', Routes\Files\FileRefsUpdate::class); + $group->delete('/file-refs/{id}', Routes\Files\FileRefsDelete::class); + $this->addRelationship( + $group, + '/file-refs/{id}/relationships/terms-of-use', + Routes\Files\Rel\TermsOfFileRef::class + ); - $this->app->map(['HEAD'], '/file-refs/{id}/content', Routes\Files\FileRefsContentHead::class); - $this->app->get('/file-refs/{id}/content', Routes\Files\FileRefsContentShow::class); - $this->app->post('/file-refs/{id}/content', Routes\Files\FileRefsContentUpdate::class); + $group->map(['HEAD'], '/file-refs/{id}/content', Routes\Files\FileRefsContentHead::class); + $group->get('/file-refs/{id}/content', Routes\Files\FileRefsContentShow::class); + $group->post('/file-refs/{id}/content', Routes\Files\FileRefsContentUpdate::class); - $this->app->get('/folders/{id}', Routes\Files\FoldersShow::class); - $this->app->patch('/folders/{id}', Routes\Files\FoldersUpdate::class); - $this->app->delete('/folders/{id}', Routes\Files\FoldersDelete::class); + $group->get('/folders/{id}', Routes\Files\FoldersShow::class); + $group->patch('/folders/{id}', Routes\Files\FoldersUpdate::class); + $group->delete('/folders/{id}', Routes\Files\FoldersDelete::class); // not a JSON route - $this->app->post('/folders/{id}/copy', Routes\Files\FoldersCopy::class); + $group->post('/folders/{id}/copy', Routes\Files\FoldersCopy::class); - $this->app->get('/folders/{id}/file-refs', Routes\Files\SubfilerefsIndex::class); - $this->app->get('/folders/{id}/folders', Routes\Files\SubfoldersIndex::class); + $group->get('/folders/{id}/file-refs', Routes\Files\SubfilerefsIndex::class); + $group->get('/folders/{id}/folders', Routes\Files\SubfoldersIndex::class); - $this->app->post('/folders/{id}/file-refs', Routes\Files\NegotiateFileRefsCreate::class); - $this->app->post('/folders/{id}/folders', Routes\Files\SubfoldersCreate::class); + $group->post('/folders/{id}/file-refs', Routes\Files\NegotiateFileRefsCreate::class); + $group->post('/folders/{id}/folders', Routes\Files\SubfoldersCreate::class); - $this->app->get('/files/{id}', Routes\Files\FilesShow::class); - $this->app->get('/files/{id}/file-refs', Routes\Files\FileRefsOfFilesShow::class); - $this->addRelationship('/files/{id}/relationships/file-refs', Routes\Files\Rel\FileRefsOfFile::class); + $group->get('/files/{id}', Routes\Files\FilesShow::class); + $group->get('/files/{id}/file-refs', Routes\Files\FileRefsOfFilesShow::class); + $this->addRelationship($group, '/files/{id}/relationships/file-refs', Routes\Files\Rel\FileRefsOfFile::class); } - private function addAuthenticatedMessagesRoutes() + private function addAuthenticatedMessagesRoutes(RouteCollectorProxy $group): void { - $this->app->get('/users/{id}/inbox', Routes\Messages\InboxShow::class); + $group->get('/users/{id}/inbox', Routes\Messages\InboxShow::class); - $this->app->get('/users/{id}/outbox', Routes\Messages\OutboxShow::class); + $group->get('/users/{id}/outbox', Routes\Messages\OutboxShow::class); - $this->app->post('/messages', Routes\Messages\MessageCreate::class); - $this->app->get('/messages/{id}', Routes\Messages\MessageShow::class); - $this->app->patch('/messages/{id}', Routes\Messages\MessageUpdate::class); - $this->app->delete('/messages/{id}', Routes\Messages\MessageDelete::class); + $group->post('/messages', Routes\Messages\MessageCreate::class); + $group->get('/messages/{id}', Routes\Messages\MessageShow::class); + $group->patch('/messages/{id}', Routes\Messages\MessageUpdate::class); + $group->delete('/messages/{id}', Routes\Messages\MessageDelete::class); } - private function addAuthenticatedForumRoutes() + private function addAuthenticatedForumRoutes(RouteCollectorProxy $group): void { - $this->app->get('/courses/{id}/forum-categories', Routes\Forum\ForumCategoriesIndex::class); + $group->get('/courses/{id}/forum-categories', Routes\Forum\ForumCategoriesIndex::class); - $this->app->get('/forum-entries/{id}', Routes\Forum\ForumEntriesShow::class); - $this->app->get('/forum-entries/{id}/entries', Routes\Forum\ForumEntryEntriesIndex::class); + $group->get('/forum-entries/{id}', Routes\Forum\ForumEntriesShow::class); + $group->get('/forum-entries/{id}/entries', Routes\Forum\ForumEntryEntriesIndex::class); - $this->app->get('/forum-categories/{id}', Routes\Forum\ForumCategoriesShow::class); + $group->get('/forum-categories/{id}', Routes\Forum\ForumCategoriesShow::class); - $this->app->get('/forum-categories/{id}/entries', Routes\Forum\ForumCategoryEntriesIndex::class); + $group->get('/forum-categories/{id}/entries', Routes\Forum\ForumCategoryEntriesIndex::class); - $this->app->post('/forum-entries/{id}/entries', Routes\Forum\ForumEntryEntriesCreate::class); - $this->app->post('/forum-categories/{id}/entries', Routes\Forum\ForumCategoryEntriesCreate::class); - $this->app->post('/courses/{id}/forum-categories', Routes\Forum\ForumCategoriesCreate::class); + $group->post('/forum-entries/{id}/entries', Routes\Forum\ForumEntryEntriesCreate::class); + $group->post('/forum-categories/{id}/entries', Routes\Forum\ForumCategoryEntriesCreate::class); + $group->post('/courses/{id}/forum-categories', Routes\Forum\ForumCategoriesCreate::class); - $this->app->patch('/forum-categories/{id}', Routes\Forum\ForumCategoriesUpdate::class); - $this->app->patch('/forum-entries/{id}', Routes\Forum\ForumEntriesUpdate::class); + $group->patch('/forum-categories/{id}', Routes\Forum\ForumCategoriesUpdate::class); + $group->patch('/forum-entries/{id}', Routes\Forum\ForumEntriesUpdate::class); - $this->app->delete('/forum-categories/{id}', Routes\Forum\ForumCategoriesDelete::class); - $this->app->delete('/forum-entries/{id}', Routes\Forum\ForumEntriesDelete::class); + $group->delete('/forum-categories/{id}', Routes\Forum\ForumCategoriesDelete::class); + $group->delete('/forum-entries/{id}', Routes\Forum\ForumEntriesDelete::class); } - private function addRelationship($url, $handler) + private function addRelationship(RouteCollectorProxy $group, string $url, string $handler): void { - $this->app->map(['GET', 'PATCH', 'POST', 'DELETE'], $url, $handler); + $group->map(['GET', 'PATCH', 'POST', 'DELETE'], $url, $handler); } } diff --git a/lib/classes/JsonApi/Routes/ActivityStreamShow.php b/lib/classes/JsonApi/Routes/ActivityStreamShow.php index 1d889cc14aa5287dc0a58d9f561431d97c5725ed..2a1a5574d30bea53153a1f56a18585e7b7fdedcf 100644 --- a/lib/classes/JsonApi/Routes/ActivityStreamShow.php +++ b/lib/classes/JsonApi/Routes/ActivityStreamShow.php @@ -14,7 +14,7 @@ use Studip\Activity\InstituteContext; use Studip\Activity\Stream; use Studip\Activity\UserContext; -function canShowActivityStream(\User $observer, $userId) +function canShowActivityStream(\User $observer, string $userId): bool { if (!$GLOBALS['perm']->have_perm('root', $observer->id)) { return true; @@ -31,7 +31,7 @@ class ActivityStreamShow extends JsonApiController protected $allowedPagingParameters = ['offset', 'limit']; - public function __invoke(Request $request, Response $response, $args) + public function __invoke(Request $request, Response $response, array $args): Response { if (!canShowActivityStream($this->getUser($request), $userId = $args['id'])) { throw new AuthorizationFailedException(); @@ -41,28 +41,18 @@ class ActivityStreamShow extends JsonApiController throw new RecordNotFoundException(); } - $urlFilter = $this->getUrlFilter($request); + $urlFilter = $this->getUrlFilter(); + /** @var \User $user */ $contexts = $this->createContexts($user); $filter = $this->createFilter($urlFilter); try { - if (!$stream = $this->createStream($contexts, $filter)) { - $data = []; - $total = 0; - } else { - list($offset, $limit) = $this->getOffsetAndLimit(); - $total = count($stream); - $data = array_slice($stream->getIterator()->getArrayCopy(), $offset, $limit); - } + $stream = $this->createStream($contexts, $filter); + list($offset, $limit) = $this->getOffsetAndLimit(); + $total = count($stream); + $data = array_slice($stream->getIterator()->getArrayCopy(), $offset, $limit); } catch (\Exception $exception) { - $error = new \Neomerx\JsonApi\Document\Error( - 'internal-server-error', - null, - 500, - 'internal-server-error', - $exception->getMessage() - ); - throw new \Neomerx\JsonApi\Exceptions\JsonApiException($error, 500); + throw new \JsonApi\Errors\InternalServerError($exception->getMessage()); } $meta = ['filter' => $urlFilter]; @@ -70,7 +60,7 @@ class ActivityStreamShow extends JsonApiController return $this->getPaginatedContentResponse($data, $total, 200, null, $meta); } - private function getUrlFilter() + private function getUrlFilter(): array { $params = $this->getQueryParameters(); $filtering = $params->getFilteringParameters(); @@ -100,7 +90,7 @@ class ActivityStreamShow extends JsonApiController return $filter; } - private function createContexts(\User $user) + private function createContexts(\User $user): array { $contexts = [ new SystemContext($user), @@ -125,7 +115,7 @@ class ActivityStreamShow extends JsonApiController return $contexts; } - private function createFilter($urlFilter) + private function createFilter(array $urlFilter): Filter { $filter = new Filter(); @@ -137,8 +127,6 @@ class ActivityStreamShow extends JsonApiController $word, [ 'activity', - // TODO: Polishing - // 'blubber', 'documents', 'forum', 'message', @@ -162,7 +150,7 @@ class ActivityStreamShow extends JsonApiController return $filter; } - private function createStream($contexts, $filter) + private function createStream(array $contexts, Filter $filter): Stream { return new Stream($contexts, $filter); } diff --git a/lib/classes/JsonApi/Routes/ArrayHelperTrait.php b/lib/classes/JsonApi/Routes/ArrayHelperTrait.php index 46ec41b29dbfe4f90c343595757cb137b5ca0db0..f39dabf35eb4d44a6b9db348278f57bd72ad5742 100644 --- a/lib/classes/JsonApi/Routes/ArrayHelperTrait.php +++ b/lib/classes/JsonApi/Routes/ArrayHelperTrait.php @@ -1,7 +1,5 @@ <?php -// TODO: das gehört bestimmt nicht in Routes - namespace JsonApi\Routes; trait ArrayHelperTrait diff --git a/lib/classes/JsonApi/Routes/Blubber/FilterTrait.php b/lib/classes/JsonApi/Routes/Blubber/FilterTrait.php index 5e12b832d1a7a8f7e434eb5bb7ddf948b90ccafb..1f043388f68733707f07e0c94fcd911bbd553e90 100644 --- a/lib/classes/JsonApi/Routes/Blubber/FilterTrait.php +++ b/lib/classes/JsonApi/Routes/Blubber/FilterTrait.php @@ -2,6 +2,8 @@ namespace JsonApi\Routes\Blubber; +use Psr\Http\Message\ServerRequestInterface as Request; + trait FilterTrait { private function validateFilters() @@ -21,7 +23,7 @@ trait FilterTrait } } - private function getFilters() + private function getFilters(): array { $filtering = $this->getQueryParameters()->getFilteringParameters() ?? []; diff --git a/lib/classes/JsonApi/Routes/Blubber/ThreadsIndex.php b/lib/classes/JsonApi/Routes/Blubber/ThreadsIndex.php index 8c12031ebe3ae1f11d9993ab2bd1446cda378f45..74f406962ef874fe83c16fa45be3e6924e131b77 100644 --- a/lib/classes/JsonApi/Routes/Blubber/ThreadsIndex.php +++ b/lib/classes/JsonApi/Routes/Blubber/ThreadsIndex.php @@ -25,8 +25,6 @@ class ThreadsIndex extends JsonApiController */ public function __invoke(Request $request, Response $response, $args) { - $this->validateFilters(); - $contextType = $args['type']; if (!in_array($contextType, ['all', 'public', 'private', 'course', 'institute'])) { throw new BadRequestException('Wrong context type.'); @@ -34,7 +32,9 @@ class ThreadsIndex extends JsonApiController switch ($contextType) { case 'all': - list($threads, $total) = $this->getAllThreads($this->getUser($request)); + $this->validateFilters(); + $filters = $this->getFilters(); + list($threads, $total) = $this->getAllThreads($filters, $this->getUser($request)); break; case 'public': @@ -57,9 +57,8 @@ class ThreadsIndex extends JsonApiController return $this->getPaginatedContentResponse($threads, $total); } - private function getAllThreads(\User $observer) + private function getAllThreads(array $filters, \User $observer) { - $filters = $this->getFilters(); list($offset, $limit) = $this->getOffsetAndLimit(); $threads = \BlubberThread::findMyGlobalThreads( diff --git a/lib/classes/JsonApi/Routes/Courses/CoursesByUserIndex.php b/lib/classes/JsonApi/Routes/Courses/CoursesByUserIndex.php index 2be3e1d01260a3461df3e70bcc49846c0fa7f7ac..2adf6d7ccb2af3edd26d638fbd90146f9736483f 100644 --- a/lib/classes/JsonApi/Routes/Courses/CoursesByUserIndex.php +++ b/lib/classes/JsonApi/Routes/Courses/CoursesByUserIndex.php @@ -34,7 +34,7 @@ class CoursesByUserIndex extends JsonApiController /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function __invoke(Request $request, Response $response, $args) + public function __invoke(Request $request, Response $response, array $args): Response { if (!$user = \User::find($args['id'])) { throw new RecordNotFoundException(); diff --git a/lib/classes/JsonApi/Routes/DiscoveryIndex.php b/lib/classes/JsonApi/Routes/DiscoveryIndex.php index 5323a2211122641dbccafba7b563ad37f5d9e33b..e5c74b1ba93415f6e81c34f3cfe69b5306365223 100644 --- a/lib/classes/JsonApi/Routes/DiscoveryIndex.php +++ b/lib/classes/JsonApi/Routes/DiscoveryIndex.php @@ -8,9 +8,9 @@ use JsonApi\JsonApiController; class DiscoveryIndex extends JsonApiController { - public function __invoke(Request $request, Response $response, $args) + public function __invoke(Request $request, Response $response) { - $routes = $this->container->get('router')->getRoutes(); + $routes = $this->container->get(\Slim\App::class)->getRouteCollector()->getRoutes(); return $this->getContentResponse($routes); } diff --git a/lib/classes/JsonApi/Routes/Events/UserEventsIcal.php b/lib/classes/JsonApi/Routes/Events/UserEventsIcal.php index a4e6da79c18286d8ccf50a86d0f0a5f443625519..2dbc4c2e33d2fd74872ea397ee51880509ce7848 100644 --- a/lib/classes/JsonApi/Routes/Events/UserEventsIcal.php +++ b/lib/classes/JsonApi/Routes/Events/UserEventsIcal.php @@ -31,9 +31,9 @@ class UserEventsIcal extends NonJsonApiController } $content = implode($export->getExport()); + $response->getBody()->write($content); return $response->withHeader('Content-Type', 'text/calendar') - ->withHeader('Content-Disposition', 'attachment; '.encode_header_parameter('filename', 'studip.ics')) - ->write($content); + ->withHeader('Content-Disposition', 'attachment; ' . encode_header_parameter('filename', 'studip.ics')); } } diff --git a/lib/classes/JsonApi/Routes/Files/FileRefsContentHead.php b/lib/classes/JsonApi/Routes/Files/FileRefsContentHead.php index a0343f5bdcc5a336ed85d2291ba14c23ff9c5d8c..93aaa95fd4db4fb50faa6f71c20afb7f4549df42 100644 --- a/lib/classes/JsonApi/Routes/Files/FileRefsContentHead.php +++ b/lib/classes/JsonApi/Routes/Files/FileRefsContentHead.php @@ -12,7 +12,7 @@ class FileRefsContentHead extends NonJsonApiController { use EtagHelperTrait; - public function invoke(Request $request, Response $response, $args) + public function invoke(Request $request, Response $response, array $args): Response { if (!$fileRef = \FileRef::find($args['id'])) { throw new RecordNotFoundException(); @@ -21,7 +21,6 @@ class FileRefsContentHead extends NonJsonApiController if (!Authority::canDownloadFileRef($this->getUser($request), $fileRef)) { throw new AuthorizationFailedException(); } - list(, $response) = $this->handleEtag($request, $response, $fileRef, true); return $response; diff --git a/lib/classes/JsonApi/Routes/Files/FileRefsCreateByUpload.php b/lib/classes/JsonApi/Routes/Files/FileRefsCreateByUpload.php index 880354c6a4395759005b0f6ffe70bb31925b0872..3bb00d1b9ed0b50a7576565e71a811424ae03821 100644 --- a/lib/classes/JsonApi/Routes/Files/FileRefsCreateByUpload.php +++ b/lib/classes/JsonApi/Routes/Files/FileRefsCreateByUpload.php @@ -12,7 +12,7 @@ class FileRefsCreateByUpload extends NonJsonApiController { use RoutesHelperTrait; - public function invoke(Request $request, Response $response, $args) + public function invoke(Request $request, Response $response, array $args): Response { if (!$folder = \FileManager::getTypedFolder($args['id'])) { throw new RecordNotFoundException(); diff --git a/lib/classes/JsonApi/Routes/Files/FoldersCopy.php b/lib/classes/JsonApi/Routes/Files/FoldersCopy.php index 60d0f79997610bb25f61c2e03d3e606c01e7b5a1..046fac118bea30d1dce2d4d31f8ea5c831b5c5f6 100644 --- a/lib/classes/JsonApi/Routes/Files/FoldersCopy.php +++ b/lib/classes/JsonApi/Routes/Files/FoldersCopy.php @@ -8,7 +8,6 @@ use JsonApi\Errors\AuthorizationFailedException; use JsonApi\Errors\BadRequestException; use JsonApi\Errors\RecordNotFoundException; use JsonApi\NonJsonApiController; -use JsonApi\Providers\JsonApiConfig as C; class FoldersCopy extends NonJsonApiController { @@ -45,7 +44,7 @@ class FoldersCopy extends NonJsonApiController { $pathinfo = $this->getSchema($folder)->getSelfSubLink($folder)->getSubHref(); $old = \URLHelper::setBaseURL($GLOBALS['ABSOLUTE_URI_STUDIP']); - $url = \URLHelper::getURL($this->container->get(C::JSON_URL_PREFIX).$pathinfo, [], true); + $url = \URLHelper::getURL($this->container->get('json-api-integration-urlPrefix').$pathinfo, [], true); \URLHelper::setBaseURL($old); return $response->withRedirect($url, 201); diff --git a/lib/classes/JsonApi/Routes/Files/NegotiateFileRefsCreate.php b/lib/classes/JsonApi/Routes/Files/NegotiateFileRefsCreate.php index 22add9e6ea6e77c01202ef8151d726e1509031f3..89e00e111a5a1a0a1510f00de353166170d75257 100644 --- a/lib/classes/JsonApi/Routes/Files/NegotiateFileRefsCreate.php +++ b/lib/classes/JsonApi/Routes/Files/NegotiateFileRefsCreate.php @@ -3,11 +3,14 @@ namespace JsonApi\Routes\Files; use Psr\Container\ContainerInterface; -use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface as Request; class NegotiateFileRefsCreate { + /** @var ContainerInterface */ + private $container; + /** * Der Konstruktor. * @@ -18,13 +21,13 @@ class NegotiateFileRefsCreate $this->container = $container; } - public function __invoke(Request $request, Response $response, $args) + public function __invoke(Request $request, Response $response, array $args): Response { $contentType = $request->getHeaderLine('Content-Type'); if ('multipart/form-data' === substr($contentType, 0, strlen('multipart/form-data'))) { - $route = new FileRefsCreateByUpload($this->container); + $route = $this->container->get(FileRefsCreateByUpload::class); } else { - $route = new FileRefsCreate($this->container); + $route = $this->container->get(FileRefsCreate::class); } return $route($request, $response, $args); diff --git a/lib/classes/JsonApi/Routes/Files/RoutesHelperTrait.php b/lib/classes/JsonApi/Routes/Files/RoutesHelperTrait.php index 3590e1419aefcead52a47769e5c4b239fa09f232..8122ec59893752417cd4ff675c589b4c62861ae8 100644 --- a/lib/classes/JsonApi/Routes/Files/RoutesHelperTrait.php +++ b/lib/classes/JsonApi/Routes/Files/RoutesHelperTrait.php @@ -4,13 +4,12 @@ namespace JsonApi\Routes\Files; use JsonApi\Errors\BadRequestException; use JsonApi\Errors\InternalServerError; -use JsonApi\Providers\JsonApiConfig as C; use JsonApi\Schemas\FileRef as FileRefSchema; use JsonApi\Schemas\Folder as FolderSchema; use JsonApi\Schemas\ContentTermsOfUse as ContentTermsOfUseSchema; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; -use Slim\Http\UploadedFile; +use Slim\Psr7\UploadedFile; trait RoutesHelperTrait { @@ -292,11 +291,11 @@ trait RoutesHelperTrait */ private function redirectToFileRef(Response $response, \FileRef $fileRef) { - $pathinfo = $this->getSchema($fileRef)->getSelfSubLink($fileRef)->getSubHref(); + $pathinfo = $this->getSchema($fileRef)->getSelfLink($fileRef)->getStringRepresentation($this->container->get('json-api-integration-urlPrefix')); $old = \URLHelper::setBaseURL($GLOBALS['ABSOLUTE_URI_STUDIP']); - $url = \URLHelper::getURL($this->container->get(C::JSON_URL_PREFIX).$pathinfo, [], true); + $url = \URLHelper::getURL($pathinfo, [], true); \URLHelper::setBaseURL($old); - return $response->withRedirect($url, 201); + return $response->withHeader('Location', $url)->withStatus(201); } } diff --git a/lib/classes/JsonApi/Routes/News/Rel/Ranges.php b/lib/classes/JsonApi/Routes/News/Rel/Ranges.php index 1ab24a478e105e2d9a78d5dfa5e5703b4c9312b3..3f90dcdcf4d25568f625c22813b18ef377c8cfde 100644 --- a/lib/classes/JsonApi/Routes/News/Rel/Ranges.php +++ b/lib/classes/JsonApi/Routes/News/Rel/Ranges.php @@ -105,7 +105,7 @@ class Ranges extends RelationshipsController return array_filter( $news->news_ranges->map(function ($range) use ($types) { if ('global' === $range->type) { - return $this->container['studip-system-object']; + return $this->getGlobalRange(); } elseif (isset($types[$range->type])) { $klass = $types[$range->type]; @@ -172,7 +172,7 @@ class Ranges extends RelationshipsController { switch ($type) { case \JsonApi\Schemas\Studip::TYPE: - return $this->container['studip-system-object']; + return $this->getGlobalRange(); case \JsonApi\Schemas\Course::TYPE: return \Course::find($rangeId); @@ -187,6 +187,11 @@ class Ranges extends RelationshipsController return null; } + private function getGlobalRange() + { + return new \JsonApi\Model\Studip(); + } + private function addRanges(\StudipNews $news, array $ranges) { foreach ($ranges as $range) { diff --git a/lib/classes/JsonApi/Routes/RelationshipsController.php b/lib/classes/JsonApi/Routes/RelationshipsController.php index 1a42113a26ebb2448faa687f4fa3c9c1e394bcd1..47b546c782b26040d03ad98edd1c8f0678d99302 100644 --- a/lib/classes/JsonApi/Routes/RelationshipsController.php +++ b/lib/classes/JsonApi/Routes/RelationshipsController.php @@ -5,7 +5,7 @@ namespace JsonApi\Routes; use JsonApi\Errors\AuthorizationFailedException; use JsonApi\Errors\UnsupportedRequestError; use JsonApi\JsonApiController; -use Neomerx\JsonApi\Contracts\Document\DocumentInterface; +use Neomerx\JsonApi\Contracts\Schema\DocumentInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; diff --git a/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php b/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php index 48477c625dd99e22334324d77295bb022cbc81c5..85cf9113e08fa9947ec72832678e3577ca231bf9 100644 --- a/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php +++ b/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php @@ -7,8 +7,7 @@ use JsonApi\Errors\RecordNotFoundException; use JsonApi\JsonApiController; use JsonApi\Models\ScheduleEntry; use JsonApi\Routes\Users\Authority; -use Neomerx\JsonApi\Contracts\Http\ResponsesInterface; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Schema\Link; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; @@ -48,13 +47,13 @@ class UserScheduleShow extends JsonApiController ScheduleEntry::findByUser_id($otherUser->id), $this->getCycles($otherUser, $semester) ), - ResponsesInterface::HTTP_OK, + 200, [Link::SELF => $this->getSelfLink($otherUser, $semester)], $this->getMeta($semester) ); } - private function getCycles(\User $user, \Semester $semester) + private function getCycles(\User $user, \Semester $semester): array { // get all virtually added seminars $stmt = \DBManager::get()->prepare( @@ -76,42 +75,41 @@ class UserScheduleShow extends JsonApiController AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id) '); $stmt->execute([ - 'userid' => $user->id, - 'begin' => $semester->beginn, + 'userid' => $user->id, + 'begin' => $semester->beginn, 'semester_id' => $semester->id, ]); return array_reduce( array_unique(array_merge($ids, $stmt->fetchFirst())), function ($cycles, $seminarId) { - return array_merge($cycles, - array_filter( - \Course::find($seminarId)->cycles->getArrayCopy(), - function ($cycle) { - return $cycle['is_visible']; - } - ) + return array_merge( + $cycles, + array_filter( + \Course::find($seminarId)->cycles->getArrayCopy(), + function ($cycle) { + return $cycle['is_visible']; + } + ) ); }, [] ); } - private function getSelfLink($user, $semester) + private function getSelfLink(\User $user, \Semester $semester): Link { - $url = $this->container['router']->pathFor( - 'get-schedule', - ['id' => $user->id], - ['filter[timestamp]' => $semester->beginn] - ); + $routeParser = $this->app->getRouteCollector()->getRouteParser(); + $url = $routeParser->urlFor('get-schedule', ['id' => $user->id], ['filter[timestamp]' => $semester->beginn]); - return new Link($url); + return new Link(false, $url, false); } - private function getMeta($semester) + private function getMeta(\Semester $semester): array { - return [ - 'semester' => $this->getResourceLocationUrl($semester), - ]; + $routeParser = $this->app->getRouteCollector()->getRouteParser(); + $url = $routeParser->urlFor('get-semester', ['id' => $semester->id]); + + return [ 'semester' => $url ]; } } diff --git a/lib/classes/JsonApi/Routes/Studip/PropertiesIndex.php b/lib/classes/JsonApi/Routes/Studip/PropertiesIndex.php index 9ca30dc5968b080a2cdca062a25e9ac7ad79aa83..8758446c6c2a6cafb226f12383f70213ed276e82 100644 --- a/lib/classes/JsonApi/Routes/Studip/PropertiesIndex.php +++ b/lib/classes/JsonApi/Routes/Studip/PropertiesIndex.php @@ -16,7 +16,7 @@ class PropertiesIndex extends JsonApiController */ public function __invoke(Request $request, Response $response, $args) { - $studip = $this->container['studip-system-object']; + $studip = new \JsonApi\Models\Studip(); return $this->getContentResponse($studip->getProperties()); } diff --git a/lib/classes/JsonApi/Routes/Users/UsersIndex.php b/lib/classes/JsonApi/Routes/Users/UsersIndex.php index f430eead8f74f7f60c4bc2773be298f75adb662d..1418354bd085e205e6a99250e3f2a996bd7ee306 100644 --- a/lib/classes/JsonApi/Routes/Users/UsersIndex.php +++ b/lib/classes/JsonApi/Routes/Users/UsersIndex.php @@ -26,7 +26,7 @@ class UsersIndex extends JsonApiController /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function __invoke(Request $request, Response $response, $args) + public function __invoke(Request $request, Response $response, $args): Response { if (!Authority::canIndexUsers($this->getUser($request))) { throw new AuthorizationFailedException(); @@ -37,13 +37,17 @@ class UsersIndex extends JsonApiController list($offset, $limit) = $this->getOffsetAndLimit(); $partSQL = \GlobalSearchUsers::getSQL($filters['search'], [], $limit + $offset); - $users = \User::findMany(array_map(function ($array) { return $array['user_id']; }, \DBManager::get()->fetchAll($partSQL))); + $users = \User::findMany( + array_map(function ($array) { + return $array['user_id']; + }, \DBManager::get()->fetchAll($partSQL)) + ); $total = (int) \DBManager::get()->fetchColumn('SELECT FOUND_ROWS() as found_rows'); return $this->getPaginatedContentResponse($users, $total); } - private function validateFilters() + private function validateFilters(): void { $filtering = $this->getQueryParameters()->getFilteringParameters() ?? []; diff --git a/lib/classes/JsonApi/Routes/Users/UsersShow.php b/lib/classes/JsonApi/Routes/Users/UsersShow.php index be9f1afeb0a5c0672629de51576f1e34317b08b6..f22aaf33a06cc9e7dae64ee401b5000e977b3b87 100644 --- a/lib/classes/JsonApi/Routes/Users/UsersShow.php +++ b/lib/classes/JsonApi/Routes/Users/UsersShow.php @@ -2,12 +2,13 @@ namespace JsonApi\Routes\Users; -use Psr\Http\Message\ResponseInterface as Response; -use Psr\Http\Message\ServerRequestInterface as Request; -use JsonApi\JsonApiController; use JsonApi\Errors\AuthorizationFailedException; use JsonApi\Errors\RecordNotFoundException; +use JsonApi\JsonApiController; use JsonApi\Schemas\User as UserSchema; +use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface as Request; +use Slim\Routing\RouteContext; class UsersShow extends JsonApiController { @@ -21,12 +22,18 @@ class UsersShow extends JsonApiController UserSchema::REL_SCHEDULE, ]; - public function __invoke(Request $request, Response $response, $args) + /** + * @return \Psr\Http\Message\ResponseInterface + */ + public function __invoke(Request $request, Response $response, array $args) { - if (isset($args['id'])) { - $observedUser = \User::find($args['id']); - } else { + $routeName = RouteContext::fromRequest($request) + ->getRoute() + ->getName(); + if ($routeName === 'get-myself') { $observedUser = $this->getUser($request); + } else { + $observedUser = \User::find($args['id']); } if (!$observedUser) { throw new RecordNotFoundException(); diff --git a/lib/classes/JsonApi/Routes/Wiki/WikiShow.php b/lib/classes/JsonApi/Routes/Wiki/WikiShow.php index 4c2a5c1fcab81cfe5bb1540fc395dfa67935b626..a01c06fab06c4d168768e23689bf1423020ae1c9 100644 --- a/lib/classes/JsonApi/Routes/Wiki/WikiShow.php +++ b/lib/classes/JsonApi/Routes/Wiki/WikiShow.php @@ -3,10 +3,7 @@ namespace JsonApi\Routes\Wiki; use JsonApi\Errors\AuthorizationFailedException; -use JsonApi\Errors\BadRequestException; use JsonApi\JsonApiController; -use Neomerx\JsonApi\Contracts\Http\ResponsesInterface; -use Neomerx\JsonApi\Document\Link; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; diff --git a/lib/classes/JsonApi/SchemaMap.php b/lib/classes/JsonApi/SchemaMap.php index 2354a0ec2c800d74ea857ea0ccf32db49fb5568c..042ee58eab29f992cda21959fe112f8349c16ee7 100644 --- a/lib/classes/JsonApi/SchemaMap.php +++ b/lib/classes/JsonApi/SchemaMap.php @@ -7,58 +7,55 @@ namespace JsonApi; */ class SchemaMap { - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function __invoke(\Slim\Container $container) + public function __invoke(): array { return [ - \Slim\Route::class => \JsonApi\Schemas\SlimRoute::class, + \Slim\Routing\Route::class => Schemas\SlimRoute::class, - \JsonApi\Models\ScheduleEntry::class => \JsonApi\Schemas\ScheduleEntry::class, + \JsonApi\Models\ScheduleEntry::class => Schemas\ScheduleEntry::class, - \BlubberComment::class => \JsonApi\Schemas\BlubberComment::class, - \BlubberStatusgruppeThread::class => \JsonApi\Schemas\BlubberStatusgruppeThread::class, - \BlubberThread::class => \JsonApi\Schemas\BlubberThread::class, + \BlubberComment::class => Schemas\BlubberComment::class, + \BlubberStatusgruppeThread::class => Schemas\BlubberStatusgruppeThread::class, + \BlubberThread::class => Schemas\BlubberThread::class, - \CalendarEvent::class => \JsonApi\Schemas\CalendarEvent::class, - \ConfigValue::class => \JsonApi\Schemas\ConfigValue::class, - \CourseEvent::class => \JsonApi\Schemas\CourseEvent::class, - \ContentTermsOfUse::class => \JsonApi\Schemas\ContentTermsOfUse::class, - \Course::class => \JsonApi\Schemas\Course::class, - \CourseMember::class => \JsonApi\Schemas\CourseMember::class, - \FeedbackElement::class => \JsonApi\Schemas\FeedbackElement::class, - \FeedbackEntry::class => \JsonApi\Schemas\FeedbackEntry::class, - \JsonApi\Models\ForumCat::class => \JsonApi\Schemas\ForumCategory::class, - \JsonApi\Models\ForumEntry::class => \JsonApi\Schemas\ForumEntry::class, - \Institute::class => \JsonApi\Schemas\Institute::class, - \InstituteMember::class => \JsonApi\Schemas\InstituteMember::class, - \Message::class => \JsonApi\Schemas\Message::class, - \SemClass::class => \JsonApi\Schemas\SemClass::class, - \Semester::class => \JsonApi\Schemas\Semester::class, - \SemType::class => \JsonApi\Schemas\SemType::class, - \SeminarCycleDate::class => \JsonApi\Schemas\SeminarCycleDate::class, - \Statusgruppen::class => \JsonApi\Schemas\StatusGroup::class, - \JsonApi\Models\Studip::class => \JsonApi\Schemas\Studip::class, - \JsonApi\Models\StudipProperty::class => \JsonApi\Schemas\StudipProperty::class, - \StudipComment::class => \JsonApi\Schemas\StudipComment::class, - \StudipNews::class => \JsonApi\Schemas\StudipNews::class, - \StudipStudyArea::class => \JsonApi\Schemas\StudyArea::class, - \WikiPage::class => \JsonApi\Schemas\WikiPage::class, - \Studip\Activity\Activity::class => \JsonApi\Schemas\Activity::class, - \User::class => \JsonApi\Schemas\User::class, - \File::class => \JsonApi\Schemas\File::class, - \FileRef::class => \JsonApi\Schemas\FileRef::class, - \FolderType::class => \JsonApi\Schemas\Folder::class, + \CalendarEvent::class => Schemas\CalendarEvent::class, + \ConfigValue::class => Schemas\ConfigValue::class, + \CourseEvent::class => Schemas\CourseEvent::class, + \ContentTermsOfUse::class => Schemas\ContentTermsOfUse::class, + \Course::class => Schemas\Course::class, + \CourseMember::class => Schemas\CourseMember::class, + \FeedbackElement::class => Schemas\FeedbackElement::class, + \FeedbackEntry::class => Schemas\FeedbackEntry::class, + \JsonApi\Models\ForumCat::class => Schemas\ForumCategory::class, + \JsonApi\Models\ForumEntry::class => Schemas\ForumEntry::class, + \Institute::class => Schemas\Institute::class, + \InstituteMember::class => Schemas\InstituteMember::class, + \Message::class => Schemas\Message::class, + \SemClass::class => Schemas\SemClass::class, + \Semester::class => Schemas\Semester::class, + \SemType::class => Schemas\SemType::class, + \SeminarCycleDate::class => Schemas\SeminarCycleDate::class, + \Statusgruppen::class => Schemas\StatusGroup::class, + \JsonApi\Models\Studip::class => Schemas\Studip::class, + \JsonApi\Models\StudipProperty::class => Schemas\StudipProperty::class, + \StudipComment::class => Schemas\StudipComment::class, + \StudipNews::class => Schemas\StudipNews::class, + \StudipStudyArea::class => Schemas\StudyArea::class, + \WikiPage::class => Schemas\WikiPage::class, + \Studip\Activity\Activity::class => Schemas\Activity::class, + \User::class => Schemas\User::class, + \File::class => Schemas\File::class, + \FileRef::class => Schemas\FileRef::class, + \FolderType::class => Schemas\Folder::class, - \Courseware\Block::class => \JsonApi\Schemas\Courseware\Block::class, - \Courseware\BlockComment::class => \JsonApi\Schemas\Courseware\BlockComment::class, - \Courseware\BlockFeedback::class => \JsonApi\Schemas\Courseware\BlockFeedback::class, - \Courseware\Container::class => \JsonApi\Schemas\Courseware\Container::class, - \Courseware\Instance::class => \JsonApi\Schemas\Courseware\Instance::class, - \Courseware\StructuralElement::class => \JsonApi\Schemas\Courseware\StructuralElement::class, - \Courseware\UserDataField::class => \JsonApi\Schemas\Courseware\UserDataField::class, - \Courseware\UserProgress::class => \JsonApi\Schemas\Courseware\UserProgress::class, + \Courseware\Block::class => Schemas\Courseware\Block::class, + \Courseware\BlockComment::class => Schemas\Courseware\BlockComment::class, + \Courseware\BlockFeedback::class => Schemas\Courseware\BlockFeedback::class, + \Courseware\Container::class => Schemas\Courseware\Container::class, + \Courseware\Instance::class => Schemas\Courseware\Instance::class, + \Courseware\StructuralElement::class => Schemas\Courseware\StructuralElement::class, + \Courseware\UserDataField::class => Schemas\Courseware\UserDataField::class, + \Courseware\UserProgress::class => Schemas\Courseware\UserProgress::class, ]; } } diff --git a/lib/classes/JsonApi/Schemas/Activity.php b/lib/classes/JsonApi/Schemas/Activity.php index 300dc15bf252f4595c32d94c591ea0acacc4d1c3..ae95e0c0ea5e671882e96a4470e0401ffcdc24e2 100644 --- a/lib/classes/JsonApi/Schemas/Activity.php +++ b/lib/classes/JsonApi/Schemas/Activity.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; use Studip\Activity\Activity as StudipActivity; class Activity extends SchemaProvider @@ -16,14 +17,14 @@ class Activity extends SchemaProvider * Hier wird der Typ des Schemas festgelegt. * {@inheritdoc} */ - protected $resourceType = self::TYPE; + /** * Diese Method entscheidet über die JSON-API-spezifische ID von * Activity-Objekten. * {@inheritdoc} */ - public function getId($activity) + public function getId($activity): ?string { return $activity->id; } @@ -33,7 +34,7 @@ class Activity extends SchemaProvider * für die Ausgabe vorbereitet werden. * {@inheritdoc} */ - public function getAttributes($activity) + public function getAttributes($activity, ContextInterface $context): iterable { if (preg_match('/\\\\([^\\\\]+)Provider$/', $activity->provider, $matches)) { $activityType = strtolower($matches[1]); @@ -57,8 +58,11 @@ class Activity extends SchemaProvider * spezifiziert werden. * {@inheritdoc} */ - public function getRelationships($activity, $isPrimary, array $includeList) + public function getRelationships($activity, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $shouldInclude = function ($key) use ($isPrimary, $includeList) { return $isPrimary && in_array($key, $includeList); }; @@ -78,9 +82,10 @@ class Activity extends SchemaProvider $actorId = $activity->actor_id; if ($actorType === 'user') { + $actor = $include ? \User::findFull($actorId) : \User::build(['id' => $actorId], false); $relationships[self::REL_ACTOR] = [ - self::LINKS => [Link::RELATED => new Link('/users/'.$actorId)], - self::DATA => $include ? \User::findFull($actorId) : \User::build(['id' => $actorId], false), + self::RELATIONSHIP_LINKS => [Link::RELATED => $this->createLinkToResource($actor)], + self::RELATIONSHIP_DATA => $actor ]; } @@ -90,8 +95,6 @@ class Activity extends SchemaProvider private function getObjectRelationship(array $relationships, StudipActivity $activity, $include) { $mapping = [ - // TODO: Polishing - // 'blubber' => \BlubberPosting::class, 'documents' => \FileRef::class, 'forum' => \JsonApi\Models\ForumEntry::class, 'message' => \Message::class, @@ -114,17 +117,17 @@ class Activity extends SchemaProvider } if ($data) { - $link = $this->getSchemaContainer()->getSchema($data)->getSelfSubLink($data); + $link = $this->createLinkToResource($data); $relationships[self::REL_OBJECT] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $link ], - self::DATA => $data, + self::RELATIONSHIP_DATA => $data, ]; } } else { $relationships[self::REL_OBJECT] = [ - self::META => [ + self::RELATIONSHIP_META => [ 'object-type' => $activity->object_type, 'object-id' => $activity->object_id, ], @@ -137,12 +140,12 @@ class Activity extends SchemaProvider private function getContextRelationship(array $relationships, StudipActivity $activity, $include) { if ($data = $this->getContext($activity, $include)) { - $link = $this->getSchemaContainer()->getSchema($data)->getSelfSubLink($data); + $link = $this->createLinkToResource($data); $relationships[self::REL_CONTEXT] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $link ], - self::DATA => $data, + self::RELATIONSHIP_DATA => $data, ]; } diff --git a/lib/classes/JsonApi/Schemas/BlubberComment.php b/lib/classes/JsonApi/Schemas/BlubberComment.php index 7d6e994ae60e315b5f3f79f4301b2070cb708175..2aabd5e19ea9e80322f9d5a32054d2c2727b6246 100644 --- a/lib/classes/JsonApi/Schemas/BlubberComment.php +++ b/lib/classes/JsonApi/Schemas/BlubberComment.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Schema\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; class BlubberComment extends SchemaProvider { @@ -11,14 +12,12 @@ class BlubberComment extends SchemaProvider const REL_MENTIONS = 'mentions'; const REL_THREAD = 'thread'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { $attributes = [ # `network` VARCHAR(64) COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, @@ -37,8 +36,11 @@ class BlubberComment extends SchemaProvider * spezifiziert werden. * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $shouldInclude = function ($key) use ($isPrimary, $includeList) { return $isPrimary && in_array($key, $includeList); }; @@ -62,12 +64,12 @@ class BlubberComment extends SchemaProvider { if (!$resource['external_contact']) { $userId = $resource['user_id']; - + $data = $includeData ? \User::find($userId) : \User::build(['id' => $userId], false); $relationships[self::REL_AUTHOR] = [ - self::LINKS => [ - Link::RELATED => new Link('/users/'.$userId), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($data), ], - self::DATA => $includeData ? \User::find($userId) : \User::build(['id' => $userId], false), + self::RELATIONSHIP_DATA => $data, ]; } @@ -85,10 +87,10 @@ class BlubberComment extends SchemaProvider } $relationships[self::REL_MENTIONS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_MENTIONS), ], - self::DATA => $relatedUsers, + self::RELATIONSHIP_DATA => $relatedUsers, ]; return $relationships; @@ -103,11 +105,10 @@ class BlubberComment extends SchemaProvider } $relationships[self::REL_THREAD] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($related)->getSelfSubLink($related), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($related), ], - self::DATA => $related, + self::RELATIONSHIP_DATA => $related, ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/BlubberStatusgruppeThread.php b/lib/classes/JsonApi/Schemas/BlubberStatusgruppeThread.php index 88cd38ebe2373e5fb47628f06f05dce889b47062..484cb6929c90c944dac2543a3f812d9f8d0ec02a 100644 --- a/lib/classes/JsonApi/Schemas/BlubberStatusgruppeThread.php +++ b/lib/classes/JsonApi/Schemas/BlubberStatusgruppeThread.php @@ -3,7 +3,8 @@ namespace JsonApi\Schemas; use JsonApi\Errors\InternalServerError; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class BlubberStatusgruppeThread extends BlubberThread { @@ -14,12 +15,15 @@ class BlubberStatusgruppeThread extends BlubberThread * spezifiziert werden. * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { - $relationships = parent::getRelationships($resource, $isPrimary, $includeList); + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + + $relationships = parent::getRelationships($resource, $context); $relationships[self::REL_STATUSGRUPPE] = [ - self::DATA => \Statusgruppen::build( + self::RELATIONSHIP_DATA => \Statusgruppen::build( [ 'statusgruppe_id' => $resource['metadata']['statusgruppe_id'] ], diff --git a/lib/classes/JsonApi/Schemas/BlubberThread.php b/lib/classes/JsonApi/Schemas/BlubberThread.php index 575da930775bb13bac464e0103ce8a2d147c7a3d..386b51e1cd1ba406502d6b447cf153cbd99f181c 100644 --- a/lib/classes/JsonApi/Schemas/BlubberThread.php +++ b/lib/classes/JsonApi/Schemas/BlubberThread.php @@ -3,7 +3,8 @@ namespace JsonApi\Schemas; use JsonApi\Errors\InternalServerError; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Schema\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; class BlubberThread extends SchemaProvider { @@ -13,25 +14,25 @@ class BlubberThread extends SchemaProvider const REL_CONTEXT = 'context'; const REL_MENTIONS = 'mentions'; - protected $resourceType = self::TYPE; - public function getId($resource) + + public function getId($resource): ?string { return $resource->id; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { - $user = $this->getDiContainer()->get('studip-current-user'); + $userId = $this->currentUser->id; $attributes = [ 'context-type' => $resource['context_type'], 'content' => $resource['content'], 'content-html' => formatReady($resource['content']), - 'is-commentable' => (bool) $resource->isCommentable($user->id), - 'is-readable' => (bool) $resource->isReadable($user->id), - 'is-writable' => (bool) $resource->isWritable($user->id), + 'is-commentable' => (bool) $resource->isCommentable($userId), + 'is-readable' => (bool) $resource->isReadable($userId), + 'is-writable' => (bool) $resource->isWritable($userId), 'is-visible-in-stream' => (bool) $resource->isVisibleInStream(), @@ -47,8 +48,11 @@ class BlubberThread extends SchemaProvider * spezifiziert werden. * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $shouldInclude = function ($key) use ($isPrimary, $includeList) { return $isPrimary && in_array($key, $includeList); }; @@ -75,11 +79,10 @@ class BlubberThread extends SchemaProvider $userId = $resource['user_id']; $related = $includeData ? \User::find($userId) : \User::build(['id' => $userId], false); $relationships[self::REL_AUTHOR] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($related)->getSelfSubLink($related), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($related), ], - self::DATA => $related, + self::RELATIONSHIP_DATA => $related, ]; } @@ -98,9 +101,9 @@ class BlubberThread extends SchemaProvider } $relationships[self::REL_MENTIONS] = [ - self::SHOW_SELF => true, - self::LINKS => [], - self::DATA => $relatedUsers, + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_LINKS => [], + self::RELATIONSHIP_DATA => $relatedUsers, ]; return $relationships; @@ -109,13 +112,13 @@ class BlubberThread extends SchemaProvider private function getCommentsRelationship(array $relationships, \BlubberThread $resource, $includeData) { $relationship = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_COMMENTS), ], ]; if ($includeData) { - $relationship[self::DATA] = $resource->comments; + $relationship[self::RELATIONSHIP_DATA] = $resource->comments; } $relationships[self::REL_COMMENTS] = $relationship; @@ -135,7 +138,7 @@ class BlubberThread extends SchemaProvider throw new InternalServerError('Inconsistent data in BlubberThread.'); } - $related = new Link('/courses/'.$course->id); + $related = $this->createLinkToResource($course); $data = $course; } @@ -144,17 +147,17 @@ class BlubberThread extends SchemaProvider throw new InternalServerError('Inconsistent data in BlubberThread.'); } - $related = new Link('/institutes/'.$institute->id); + $related = $this->createLinkToResource($institute); $data = $institute; } if ($related && $data) { $relationships[self::REL_CONTEXT] = [ - self::SHOW_SELF => true, - self::LINKS => [ + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_LINKS => [ Link::RELATED => $related, ], - self::DATA => $data, + self::RELATIONSHIP_DATA => $data, ]; } diff --git a/lib/classes/JsonApi/Schemas/CalendarEvent.php b/lib/classes/JsonApi/Schemas/CalendarEvent.php index 95fb1d9ee008d1c4d1b9a821279d8be5ef2c68e6..3ee6ab5f34b59b683790bbb831eccfdac20e8ad1 100644 --- a/lib/classes/JsonApi/Schemas/CalendarEvent.php +++ b/lib/classes/JsonApi/Schemas/CalendarEvent.php @@ -2,21 +2,20 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class CalendarEvent extends SchemaProvider { const TYPE = 'calendar-events'; const REL_OWNER = 'owner'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'title' => $resource->title, @@ -36,14 +35,17 @@ class CalendarEvent extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; if ($owner = $resource->getOwner()) { - $link = $this->getSchemaContainer()->getSchema($owner)->getSelfSubLink($owner); + $link = $this->createLinkToResource($owner); $relationships = [ - self::REL_OWNER => [self::LINKS => [Link::RELATED => $link], self::DATA => $owner], + self::REL_OWNER => [self::RELATIONSHIP_LINKS => [Link::RELATED => $link], self::RELATIONSHIP_DATA => $owner], ]; } diff --git a/lib/classes/JsonApi/Schemas/ConfigValue.php b/lib/classes/JsonApi/Schemas/ConfigValue.php index 3e75317088bb6d1de90388259c4da50b3fa1754a..e24c5943f76a55993b8bf16278bc2f9ae9599fe9 100644 --- a/lib/classes/JsonApi/Schemas/ConfigValue.php +++ b/lib/classes/JsonApi/Schemas/ConfigValue.php @@ -2,18 +2,18 @@ namespace JsonApi\Schemas; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; + class ConfigValue extends SchemaProvider { const TYPE = 'config-values'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return join('_', [$resource['range_id'], $resource['field']]); } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { $i18nAwareCast = function ($mixed) use ($resource) { return 'i18n' === $resource->entry['type'] ? (string) $mixed : $mixed; @@ -29,4 +29,9 @@ class ConfigValue extends SchemaProvider 'chdate' => date('c', $resource['chdate']), ]; } + + public function getRelationships($user, ContextInterface $context): iterable + { + return []; + } } diff --git a/lib/classes/JsonApi/Schemas/ConsultationBlock.php b/lib/classes/JsonApi/Schemas/ConsultationBlock.php index fd01004dd3a15082e1f94d26b66b5c2a67e6ebcb..75a29df11b38fdc7f98693a63672ea31aa3b8fa5 100644 --- a/lib/classes/JsonApi/Schemas/ConsultationBlock.php +++ b/lib/classes/JsonApi/Schemas/ConsultationBlock.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class ConsultationBlock extends SchemaProvider { @@ -10,14 +11,12 @@ class ConsultationBlock extends SchemaProvider const REL_SLOTS = 'slots'; const REL_RANGE = 'range'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { $attributes = [ 'start' => date('c', $resource->start), @@ -47,8 +46,11 @@ class ConsultationBlock extends SchemaProvider * spezifiziert werden. * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $shouldInclude = function ($key) use ($isPrimary, $includeList) { return $isPrimary && in_array($key, $includeList); }; @@ -78,10 +80,10 @@ class ConsultationBlock extends SchemaProvider } $relationships[self::REL_SLOTS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_SLOTS), ], - self::DATA => $relatedSlots, + self::RELATIONSHIP_DATA => $relatedSlots, ]; return $relationships; @@ -92,10 +94,10 @@ class ConsultationBlock extends SchemaProvider $range = $resource->range; $relationships[self::REL_RANGE] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getLinkForRange($range), ], - self::DATA => $includeData ? $range : $this->getMinimalRange($range), + self::RELATIONSHIP_DATA => $includeData ? $range : $this->getMinimalRange($range), ]; return $relationships; @@ -103,16 +105,12 @@ class ConsultationBlock extends SchemaProvider private function getLinkForRange(Range $range) { - if ($range instanceof \Course) { - return new Link("/courses/{$range->id}"); - } - - if ($range instanceof \Institute) { - return new Link("/institutes/{$range->id}"); - } - - if ($range instanceof \User) { - return new Link("/users/{$range->id}"); + if ( + $range instanceof \Course || + $range instanceof \Institute || + $range instanceof \User + ) { + return $this->createLinkToResource($range); } throw new \Exception('Unknown range type'); diff --git a/lib/classes/JsonApi/Schemas/ConsultationBooking.php b/lib/classes/JsonApi/Schemas/ConsultationBooking.php index 7fbc3c9490a9ce3af1fbe7222aaa31b42acc6f81..318f306f74039e33dc0d8f3f2b33634c834239ef 100644 --- a/lib/classes/JsonApi/Schemas/ConsultationBooking.php +++ b/lib/classes/JsonApi/Schemas/ConsultationBooking.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class ConsultationBooking extends SchemaProvider { @@ -10,14 +11,12 @@ class ConsultationBooking extends SchemaProvider const REL_SLOT = 'slot'; const REL_USER = 'user'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { $attributes = [ 'reason' => $resource->reason, @@ -34,8 +33,11 @@ class ConsultationBooking extends SchemaProvider * spezifiziert werden. * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $shouldInclude = function ($key) use ($isPrimary, $includeList) { return $isPrimary && in_array($key, $includeList); }; @@ -54,10 +56,10 @@ class ConsultationBooking extends SchemaProvider $slot = $resource->slot; $relationships[self::REL_SLOT] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_SLOT), ], - self::DATA => $includeData ? $slot : \ConsultationSlot::build(['id' => $slot->id], false), + self::RELATIONSHIP_DATA => $includeData ? $slot : \ConsultationSlot::build(['id' => $slot->id], false), ]; return $relationships; @@ -68,10 +70,10 @@ class ConsultationBooking extends SchemaProvider $user = $resource->user; $relationships[self::REL_USER] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_USER), ], - self::DATA => $includeData ? $user : \User::build(['id' => $user->id], false), + self::RELATIONSHIP_DATA => $includeData ? $user : \User::build(['id' => $user->id], false), ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/ConsultationSlot.php b/lib/classes/JsonApi/Schemas/ConsultationSlot.php index 7f4f7b8c3bbc514eb84d0d092461f5651d965cbd..1adf912be57de1458faba0a92356e11988a8e934 100644 --- a/lib/classes/JsonApi/Schemas/ConsultationSlot.php +++ b/lib/classes/JsonApi/Schemas/ConsultationSlot.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class ConsultationSlot extends SchemaProvider { @@ -10,14 +11,14 @@ class ConsultationSlot extends SchemaProvider const REL_BLOCK = 'block'; const REL_BOOKINGS = 'bookings'; - protected $resourceType = self::TYPE; - public function getId($resource) + + public function getId($resource): ?string { return $resource->id; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { $attributes = [ 'note' => $resource->note, @@ -38,8 +39,11 @@ class ConsultationSlot extends SchemaProvider * spezifiziert werden. * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $shouldInclude = function ($key) use ($isPrimary, $includeList) { return $isPrimary && in_array($key, $includeList); }; @@ -63,10 +67,10 @@ class ConsultationSlot extends SchemaProvider $block = $resource->block; $relationships[self::REL_BLOCK] = [ - self::LINKS => [ - Link::RELATED => new Link("/consultation-block/{$block->id}"), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($block), ], - self::DATA => $includeData ? $block : \ConsultationBlock::build(['id' => $block->id], false), + self::RELATIONSHIP_DATA => $includeData ? $block : \ConsultationBlock::build(['id' => $block->id], false), ]; return $relationships; @@ -83,10 +87,10 @@ class ConsultationSlot extends SchemaProvider } $relationships[self::REL_BOOKINGS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_BOOKINGS), ], - self::DATA => $relatedBookings, + self::RELATIONSHIP_DATA => $relatedBookings, ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/ContentTermsOfUse.php b/lib/classes/JsonApi/Schemas/ContentTermsOfUse.php index 651b408c3ea464dd6ba2e4371d79ef71770473c5..b827788e1fcc79b567ba47114b7a0196f9d130ae 100644 --- a/lib/classes/JsonApi/Schemas/ContentTermsOfUse.php +++ b/lib/classes/JsonApi/Schemas/ContentTermsOfUse.php @@ -2,18 +2,18 @@ namespace JsonApi\Schemas; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; + class ContentTermsOfUse extends SchemaProvider { const TYPE = 'terms-of-use'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'name' => (string) $resource['name'], @@ -24,4 +24,9 @@ class ContentTermsOfUse extends SchemaProvider 'chdate' => date('c', $resource['chdate']), ]; } + + public function getRelationships($user, ContextInterface $context): iterable + { + return []; + } } diff --git a/lib/classes/JsonApi/Schemas/Course.php b/lib/classes/JsonApi/Schemas/Course.php index 3aa6711e03dab0615a9cd8d8e64e3bfa5a5636f0..98c890916f49e6125e3c46b9f785a8a47744f8be 100644 --- a/lib/classes/JsonApi/Schemas/Course.php +++ b/lib/classes/JsonApi/Schemas/Course.php @@ -3,7 +3,8 @@ namespace JsonApi\Schemas; use JsonApi\Routes\Files\Authority as FilesAuth; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class Course extends SchemaProvider { @@ -26,14 +27,12 @@ class Course extends SchemaProvider const REL_STATUS_GROUPS = 'status-groups'; const REL_WIKI_PAGES = 'wiki-pages'; - protected $resourceType = self::TYPE; - - public function getId($course) + public function getId($course): ?string { return $course->seminar_id; } - public function getAttributes($course) + public function getAttributes($course, ContextInterface $context): iterable { $stringOrNull = function ($item) { return trim($item) != '' ? (string) $item : null; @@ -54,8 +53,12 @@ class Course extends SchemaProvider ]; } - public function getRelationships($course, $isPrimary, array $includeList) + public function getRelationships($course, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + + $relationships = []; $relationships[self::REL_INSTITUTE] = $this->getInstitute($course, in_array(self::REL_INSTITUTE, $includeList)); @@ -89,10 +92,10 @@ class Course extends SchemaProvider private function getInstitute(\Course $course, $shouldInclude) { return [ - self::LINKS => [ - Link::RELATED => new Link('/institutes/'.$course->institut_id), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($course->home_institut), ], - self::DATA => $course->home_institut, + self::RELATIONSHIP_DATA => $course->home_institut, ]; } @@ -103,10 +106,10 @@ class Course extends SchemaProvider } return [ - self::LINKS => [ - Link::RELATED => new Link('/semesters/'.$semester->id), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($semester), ], - self::DATA => $semester, + self::RELATIONSHIP_DATA => $semester, ]; } @@ -117,29 +120,29 @@ class Course extends SchemaProvider } return [ - self::LINKS => [ - Link::RELATED => new Link('/semesters/'.$semester->id), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($semester), ], - self::DATA => $semester, + self::RELATIONSHIP_DATA => $semester, ]; } private function getFilesRelationship(array $relationships, \Course $resource) { - $user = $this->getDiContainer()->get('studip-current-user'); + $user = $this->currentUser; if ($user && FilesAuth::canShowFileArea($user, $resource)) { $filesLink = $this->getRelationshipRelatedLink($resource, self::REL_FILES); $relationships[self::REL_FILES] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $filesLink, ], ]; $foldersLink = $this->getRelationshipRelatedLink($resource, self::REL_FOLDERS); $relationships[self::REL_FOLDERS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $foldersLink, ], ]; @@ -157,7 +160,7 @@ class Course extends SchemaProvider $includeData ) { $relationships[self::REL_FORUM_CATEGORIES] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($course, self::REL_FORUM_CATEGORIES) ], ]; @@ -174,7 +177,7 @@ class Course extends SchemaProvider $includeData ) { $relationships[self::REL_BLUBBER] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($course, self::REL_BLUBBER), ], ]; @@ -191,7 +194,7 @@ class Course extends SchemaProvider $includeData ) { $relationships[self::REL_EVENTS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($course, self::REL_EVENTS) ], ]; @@ -210,7 +213,7 @@ class Course extends SchemaProvider if (\Feedback::isActivated($course->id)) { $relationships[self::REL_FEEDBACK] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($course, self::REL_FEEDBACK) ], ]; @@ -228,8 +231,8 @@ class Course extends SchemaProvider $includeData ) { $relationships[self::REL_MEMBERSHIPS] = [ - self::SHOW_SELF => true, - self::LINKS => [ + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($course, self::REL_MEMBERSHIPS) ], ]; @@ -246,7 +249,7 @@ class Course extends SchemaProvider $includeData ) { $relationships[self::REL_NEWS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($course, self::REL_NEWS) ], ]; @@ -263,7 +266,7 @@ class Course extends SchemaProvider $includeData ) { $relationships[self::REL_WIKI_PAGES] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($course, self::REL_WIKI_PAGES) ], ]; @@ -286,7 +289,7 @@ class Course extends SchemaProvider ); $relationships[self::REL_PARTICIPATING_INSTITUTES] = [ - self::DATA => $institutes + self::RELATIONSHIP_DATA => $institutes ]; return $relationships; @@ -301,7 +304,7 @@ class Course extends SchemaProvider $includeData ) { $relationships[self::REL_SEM_CLASS] = [ - self::DATA => $course->getSemClass() + self::RELATIONSHIP_DATA => $course->getSemClass() ]; return $relationships; @@ -316,7 +319,7 @@ class Course extends SchemaProvider $includeData ) { $relationships[self::REL_SEM_TYPE] = [ - self::DATA => $course->getSemType() + self::RELATIONSHIP_DATA => $course->getSemType() ]; return $relationships; @@ -328,13 +331,13 @@ class Course extends SchemaProvider $includeData ) { $relation = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_STATUS_GROUPS), ] ]; if (in_array(self::REL_STATUS_GROUPS, $includeData)) { $related = \Statusgruppen::findBySeminar_id($resource->id); - $relation[self::DATA] = $related; + $relation[self::RELATIONSHIP_DATA] = $related; } return array_merge($relationships, [self::REL_STATUS_GROUPS => $relation]); diff --git a/lib/classes/JsonApi/Schemas/CourseEvent.php b/lib/classes/JsonApi/Schemas/CourseEvent.php index 470d86bbb0f9d6972852337d0600c9e3785672fd..d2ec52dd6b6673622387b9f8277ebed56cd0c867 100644 --- a/lib/classes/JsonApi/Schemas/CourseEvent.php +++ b/lib/classes/JsonApi/Schemas/CourseEvent.php @@ -2,21 +2,20 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class CourseEvent extends SchemaProvider { const TYPE = 'course-events'; const REL_OWNER = 'owner'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'title' => $resource->title, @@ -35,14 +34,17 @@ class CourseEvent extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; if ($owner = $resource->course) { - $link = $this->getSchemaContainer()->getSchema($owner)->getSelfSubLink($owner); + $link = $this->createLinkToResource($owner); $relationships = [ - self::REL_OWNER => [self::LINKS => [Link::RELATED => $link], self::DATA => $owner], + self::REL_OWNER => [self::RELATIONSHIP_LINKS => [Link::RELATED => $link], self::RELATIONSHIP_DATA => $owner], ]; } diff --git a/lib/classes/JsonApi/Schemas/CourseMember.php b/lib/classes/JsonApi/Schemas/CourseMember.php index 8882c84e5e13d3bd1853a99f5f58b122f33d697c..1997e8b7d02649173a68ae99823833f7dff0e1d2 100644 --- a/lib/classes/JsonApi/Schemas/CourseMember.php +++ b/lib/classes/JsonApi/Schemas/CourseMember.php @@ -4,7 +4,8 @@ namespace JsonApi\Schemas; use JsonApi\Routes\Courses\Authority as CourseAuthority; use JsonApi\Routes\CourseMemberships\Authority as MembershipAuthority; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class CourseMember extends SchemaProvider { @@ -12,14 +13,12 @@ class CourseMember extends SchemaProvider const REL_COURSE = 'course'; const REL_USER = 'user'; - protected $resourceType = self::TYPE; - - public function getId($membership) + public function getId($membership): ?string { return $membership->id; } - public function getAttributes($membership) + public function getAttributes($membership, ContextInterface $context): iterable { $attributes = [ 'permission' => $membership->status, @@ -28,14 +27,13 @@ class CourseMember extends SchemaProvider 'mkdate' => date('c', $membership->mkdate), 'label' => $membership->label, ]; - // TODO: "bind_calendar": "1", - if ($user = $this->getDiContainer()->get('studip-current-user')) { - if (MembershipAuthority::canIndexMembershipsOfUser($user, $membership->user)) { + if ($this->currentUser) { + if (MembershipAuthority::canIndexMembershipsOfUser($this->currentUser, $membership->user)) { # TODO: $attributes['notification'] = (int) $membership->notification; $attributes['visible'] = $membership->visible; } - if (CourseAuthority::canEditCourse($user, $membership->course)) { + if (CourseAuthority::canEditCourse($this->currentUser, $membership->course)) { $attributes['comment'] = $membership->comment; $attributes['visible'] = $membership->visible; } @@ -44,23 +42,26 @@ class CourseMember extends SchemaProvider return $attributes; } - public function getRelationships($membership, $isPrimary, array $includeList) + public function getRelationships($membership, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; if ($isPrimary) { $relationships[self::REL_COURSE] = [ - self::LINKS => [ - Link::RELATED => new Link('/courses/'.$membership->seminar_id), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($membership->course) ], - self::DATA => $membership->course, + self::RELATIONSHIP_DATA => $membership->course, ]; $relationships[self::REL_USER] = [ - self::LINKS => [ - Link::RELATED => new Link('/users/'.$membership->user_id), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($membership->user) ], - self::DATA => $membership->user, + self::RELATIONSHIP_DATA => $membership->user, ]; } diff --git a/lib/classes/JsonApi/Schemas/Courseware/Block.php b/lib/classes/JsonApi/Schemas/Courseware/Block.php index 23c4eae3cb7b26f31a202af5dfb696adfd12c552..89434d976f2a413112f9d6d378c22310f1e4c229 100755 --- a/lib/classes/JsonApi/Schemas/Courseware/Block.php +++ b/lib/classes/JsonApi/Schemas/Courseware/Block.php @@ -5,7 +5,8 @@ namespace JsonApi\Schemas\Courseware; use Courseware\UserDataField; use Courseware\UserProgress; use JsonApi\Schemas\SchemaProvider; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class Block extends SchemaProvider { @@ -21,12 +22,10 @@ class Block extends SchemaProvider const REL_USERPROGRESS = 'user-progress'; const REL_FILES = 'file-refs'; - protected $resourceType = self::TYPE; - /** * {@inheritdoc} */ - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } @@ -34,7 +33,7 @@ class Block extends SchemaProvider /** * {@inheritdoc} */ - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'position' => (int) $resource['position'], @@ -50,87 +49,82 @@ class Block extends SchemaProvider /** * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $relationships[self::REL_COMMENTS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_COMMENTS), ], - self::DATA => $resource->comments, + self::RELATIONSHIP_DATA => $resource->comments, ]; $relationships[self::REL_CONTAINER] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->container) - ->getSelfSubLink($resource->container), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->container), ], - self::DATA => $resource->container, + self::RELATIONSHIP_DATA => $resource->container, ]; $relationships[self::REL_OWNER] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->owner) - ->getSelfSubLink($resource->owner), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->owner), ], - self::DATA => $resource->owner, + self::RELATIONSHIP_DATA => $resource->owner, ]; $relationships[self::REL_EDITOR] = $resource['editor_id'] ? [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->editor) - ->getSelfSubLink($resource->editor), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->editor), ], - self::DATA => $resource->editor, + self::RELATIONSHIP_DATA => $resource->editor, ] - : [self::DATA => null]; + : [self::RELATIONSHIP_DATA => null]; $relationships[self::REL_EDITBLOCKER] = $resource['edit_blocker_id'] ? [ - self::SHOW_SELF => true, - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->edit_blocker) - ->getSelfSubLink($resource->edit_blocker), + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->edit_blocker), ], - self::DATA => $resource->edit_blocker, + self::RELATIONSHIP_DATA => $resource->edit_blocker, ] - : [self::SHOW_SELF => true, self::DATA => null]; + : [self::RELATIONSHIP_LINKS_SELF => true, self::RELATIONSHIP_DATA => null]; $relationships[self::REL_FEEDBACK] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_FEEDBACK), ], ]; - $user = $this->getDiContainer()->get('studip-current-user'); + $user = $this->currentUser; $userDataField = UserDataField::getUserDataField($user, $resource); $relationships[self::REL_USERDATAFIELD] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_USERDATAFIELD), ], - self::DATA => $userDataField, + self::RELATIONSHIP_DATA => $userDataField, ]; $userProgress = UserProgress::getUserProgress($user, $resource); $relationships[self::REL_USERPROGRESS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_USERPROGRESS), ], - self::DATA => $userProgress, + self::RELATIONSHIP_DATA => $userProgress, ]; if ($resource->files) { $filesLink = $this->getRelationshipRelatedLink($resource, self::REL_FILES); $relationships[self::REL_FILES] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $filesLink, ], ]; diff --git a/lib/classes/JsonApi/Schemas/Courseware/BlockComment.php b/lib/classes/JsonApi/Schemas/Courseware/BlockComment.php index fa13d55b7f5ebd4ac8c75f330fc844fece45eaf1..c2abd5bf1b74c5bf77aefb885badaeaa06d09db8 100755 --- a/lib/classes/JsonApi/Schemas/Courseware/BlockComment.php +++ b/lib/classes/JsonApi/Schemas/Courseware/BlockComment.php @@ -3,7 +3,8 @@ namespace JsonApi\Schemas\Courseware; use JsonApi\Schemas\SchemaProvider; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class BlockComment extends SchemaProvider { @@ -12,12 +13,10 @@ class BlockComment extends SchemaProvider const REL_BLOCK = 'block'; const REL_USER = 'user'; - protected $resourceType = self::TYPE; - /** * {@inheritdoc} */ - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } @@ -25,7 +24,7 @@ class BlockComment extends SchemaProvider /** * {@inheritdoc} */ - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'comment' => (string) $resource['comment'], @@ -37,26 +36,25 @@ class BlockComment extends SchemaProvider /** * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $relationships[self::REL_BLOCK] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->block) - ->getSelfSubLink($resource->block), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->block), ], - self::DATA => $resource->block, + self::RELATIONSHIP_DATA => $resource->block, ]; $relationships[self::REL_USER] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->user) - ->getSelfSubLink($resource->user), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->user), ], - self::DATA => $resource->user, + self::RELATIONSHIP_DATA => $resource->user, ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/Courseware/BlockFeedback.php b/lib/classes/JsonApi/Schemas/Courseware/BlockFeedback.php index 5e5b2c60544c78243f2d8d4dbc5cb469c5bf7db8..b5992b7c2e096257cd86d3634faf8a8be1822553 100755 --- a/lib/classes/JsonApi/Schemas/Courseware/BlockFeedback.php +++ b/lib/classes/JsonApi/Schemas/Courseware/BlockFeedback.php @@ -3,7 +3,8 @@ namespace JsonApi\Schemas\Courseware; use JsonApi\Schemas\SchemaProvider; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class BlockFeedback extends SchemaProvider { @@ -12,12 +13,10 @@ class BlockFeedback extends SchemaProvider const REL_USER = 'user'; const REL_BLOCK = 'block'; - protected $resourceType = self::TYPE; - /** * {@inheritdoc} */ - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } @@ -25,7 +24,7 @@ class BlockFeedback extends SchemaProvider /** * {@inheritdoc} */ - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'feedback' => (string) $resource['feedback'], @@ -37,26 +36,25 @@ class BlockFeedback extends SchemaProvider /** * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $relationships[self::REL_BLOCK] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->block) - ->getSelfSubLink($resource->block), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->block), ], - self::DATA => $resource->block, + self::RELATIONSHIP_DATA => $resource->block, ]; $relationships[self::REL_USER] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->user) - ->getSelfSubLink($resource->user), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->user), ], - self::DATA => $resource->user, + self::RELATIONSHIP_DATA => $resource->user, ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/Courseware/Container.php b/lib/classes/JsonApi/Schemas/Courseware/Container.php index db68fc796824b21a5a51843b1b08552007a639c1..ea6ab96957bc6ce6ba6b43ba83a891826175cb6b 100755 --- a/lib/classes/JsonApi/Schemas/Courseware/Container.php +++ b/lib/classes/JsonApi/Schemas/Courseware/Container.php @@ -3,7 +3,8 @@ namespace JsonApi\Schemas\Courseware; use JsonApi\Schemas\SchemaProvider; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class Container extends SchemaProvider { @@ -15,12 +16,10 @@ class Container extends SchemaProvider const REL_EDITBLOCKER = 'edit-blocker'; const REL_STRUCTURAL_ELEMENT = 'structural-element'; - protected $resourceType = self::TYPE; - /** * {@inheritdoc} */ - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } @@ -28,7 +27,7 @@ class Container extends SchemaProvider /** * {@inheritdoc} */ - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'position' => (int) $resource['position'], @@ -46,8 +45,11 @@ class Container extends SchemaProvider /** * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $shouldInclude = function ($key) use ($includeList) { @@ -58,48 +60,40 @@ class Container extends SchemaProvider $relationships[self::REL_OWNER] = $resource['owner_id'] ? [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->owner) - ->getSelfSubLink($resource->owner), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->owner), ], - self::DATA => $resource->owner, + self::RELATIONSHIP_DATA => $resource->owner, ] - : [self::DATA => $resource->owner]; + : [self::RELATIONSHIP_DATA => $resource->owner]; $relationships[self::REL_EDITOR] = $resource['editor_id'] ? [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->editor) - ->getSelfSubLink($resource->editor), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->editor), ], - self::DATA => $resource->editor, + self::RELATIONSHIP_DATA => $resource->editor, ] - : [self::DATA => null]; + : [self::RELATIONSHIP_DATA => null]; $relationships[self::REL_EDITBLOCKER] = $resource['edit_blocker_id'] ? [ - self::SHOW_SELF => true, - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->edit_blocker) - ->getSelfSubLink($resource->edit_blocker), + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->edit_blocker), ], - self::DATA => $resource->edit_blocker, + self::RELATIONSHIP_DATA => $resource->edit_blocker, ] - : [self::SHOW_SELF => true, self::DATA => null]; + : [self::RELATIONSHIP_LINKS_SELF => true, self::RELATIONSHIP_DATA => null]; $relationships[self::REL_STRUCTURAL_ELEMENT] = $resource['structural_element_id'] ? [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->structural_element) - ->getSelfSubLink($resource->structural_element), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->structural_element), ], - self::DATA => $resource->structural_element, + self::RELATIONSHIP_DATA => $resource->structural_element, ] - : [self::DATA => null]; + : [self::RELATIONSHIP_DATA => null]; return $relationships; } @@ -107,13 +101,13 @@ class Container extends SchemaProvider private function addBlocksRelationship(array $relationships, $resource, $includeData) { $relation = [ - self::SHOW_SELF => true, - self::LINKS => [ + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_BLOCKS), ], ]; - $relation[self::DATA] = $resource->blocks; + $relation[self::RELATIONSHIP_DATA] = $resource->blocks; $relationships[self::REL_BLOCKS] = $relation; diff --git a/lib/classes/JsonApi/Schemas/Courseware/Instance.php b/lib/classes/JsonApi/Schemas/Courseware/Instance.php index 55a70f6d6ec5c3beac2ea4bd2f53a7bd9b9c564a..2fba0e3995b0485ba7670cf25b5d7b846b1285cb 100755 --- a/lib/classes/JsonApi/Schemas/Courseware/Instance.php +++ b/lib/classes/JsonApi/Schemas/Courseware/Instance.php @@ -3,7 +3,8 @@ namespace JsonApi\Schemas\Courseware; use JsonApi\Schemas\SchemaProvider; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class Instance extends SchemaProvider { @@ -12,12 +13,10 @@ class Instance extends SchemaProvider const REL_BOOKMARKS = 'bookmarks'; const REL_ROOT = 'root'; - protected $resourceType = self::TYPE; - /** * {@inheritdoc} */ - public function getId($resource) + public function getId($resource): ?string { $root = $resource->getRoot(); @@ -27,9 +26,9 @@ class Instance extends SchemaProvider /** * {@inheritdoc} */ - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { - $user = $this->getDiContainer()->get('studip-current-user'); + $user = $this->currentUser; return [ 'block-types' => array_map([$this, 'mapBlockType'], $resource->getBlockTypes()), @@ -70,26 +69,27 @@ class Instance extends SchemaProvider /** * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; - $user = $this->getDiContainer()->get('studip-current-user'); + $user = $this->currentUser; $relationships[self::REL_BOOKMARKS] = [ - self::SHOW_SELF => true, - self::LINKS => [ + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_BOOKMARKS), ], - self::DATA => $resource->getUsersBookmarks($user), + self::RELATIONSHIP_DATA => $resource->getUsersBookmarks($user), ]; $relationships[self::REL_ROOT] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->getRoot()) - ->getSelfSubLink($resource->getRoot()), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->getRoot()), ], - self::DATA => $resource->getRoot(), + self::RELATIONSHIP_DATA => $resource->getRoot(), ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/Courseware/StructuralElement.php b/lib/classes/JsonApi/Schemas/Courseware/StructuralElement.php index 6089b47bc6e7922f8752d9e678a623c15c2a9659..ed3e32d423e01ccb3983d6d6d1abf07666db1198 100755 --- a/lib/classes/JsonApi/Schemas/Courseware/StructuralElement.php +++ b/lib/classes/JsonApi/Schemas/Courseware/StructuralElement.php @@ -3,7 +3,8 @@ namespace JsonApi\Schemas\Courseware; use JsonApi\Schemas\SchemaProvider; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class StructuralElement extends SchemaProvider { @@ -21,12 +22,10 @@ class StructuralElement extends SchemaProvider const REL_PARENT = 'parent'; const REL_USER = 'user'; - protected $resourceType = self::TYPE; - /** * {@inheritdoc} */ - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } @@ -34,9 +33,9 @@ class StructuralElement extends SchemaProvider /** * {@inheritdoc} */ - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { - $user = $this->getDiContainer()->get('studip-current-user'); + $user = $this->currentUser; return [ 'position' => (int) $resource['position'], @@ -65,8 +64,11 @@ class StructuralElement extends SchemaProvider * @param bool $isPrimary * @param array $includeList */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $shouldInclude = function ($key) use ($includeList) { @@ -74,86 +76,74 @@ class StructuralElement extends SchemaProvider }; $relationships[self::REL_CHILDREN] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_CHILDREN), ], - self::DATA => $resource->children, + self::RELATIONSHIP_DATA => $resource->children, ]; $relationships[self::REL_CONTAINERS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_CONTAINERS), ], - self::DATA => $resource->containers, + self::RELATIONSHIP_DATA => $resource->containers, ]; if ($resource->course) { $relationships[self::REL_COURSE] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->course) - ->getSelfSubLink($resource->course), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->course), ], - self::DATA => $resource->course, + self::RELATIONSHIP_DATA => $resource->course, ]; } if ($resource->user) { $relationships[self::REL_USER] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->user) - ->getSelfSubLink($resource->user), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->user), ], - self::DATA => $resource->user, + self::RELATIONSHIP_DATA => $resource->user, ]; } $relationships[self::REL_OWNER] = $resource['owner_id'] ? [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->owner) - ->getSelfSubLink($resource->owner), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->owner), ], - self::DATA => $resource->owner, + self::RELATIONSHIP_DATA => $resource->owner, ] - : [self::DATA => null]; + : [self::RELATIONSHIP_DATA => null]; $relationships[self::REL_EDITOR] = $resource['editor_id'] ? [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->editor) - ->getSelfSubLink($resource->editor), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->editor), ], - self::DATA => $resource->editor, + self::RELATIONSHIP_DATA => $resource->editor, ] - : [self::DATA => $resource->editor]; + : [self::RELATIONSHIP_DATA => $resource->editor]; $relationships[self::REL_EDITBLOCKER] = $resource['edit_blocker_id'] ? [ - self::SHOW_SELF => true, - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->edit_blocker) - ->getSelfSubLink($resource->edit_blocker), + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->edit_blocker), ], - self::DATA => $resource->edit_blocker, + self::RELATIONSHIP_DATA => $resource->edit_blocker, ] - : [self::SHOW_SELF => true, self::DATA => null]; + : [self::RELATIONSHIP_LINKS_SELF => true, self::RELATIONSHIP_DATA => null]; $relationships[self::REL_PARENT] = $resource->parent_id ? [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->parent) - ->getSelfSubLink($resource->parent), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->parent), ], - self::DATA => $resource->parent, + self::RELATIONSHIP_DATA => $resource->parent, ] - : [self::DATA => null]; + : [self::RELATIONSHIP_DATA => null]; $relationships = $this->addAncestorsRelationship( $relationships, @@ -174,14 +164,14 @@ class StructuralElement extends SchemaProvider private function addAncestorsRelationship(array $relationships, $resource, $includeData) { $relation = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_ANCESTORS), ], ]; if ($includeData) { $related = $resource->findAncestors(); - $relation[self::DATA] = $related; + $relation[self::RELATIONSHIP_DATA] = $related; } $relationships[self::REL_ANCESTORS] = $relation; @@ -192,14 +182,14 @@ class StructuralElement extends SchemaProvider private function addDescendantsRelationship(array $relationships, $resource, $includeData) { $relation = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_DESCENDANTS), ], ]; if ($includeData) { $related = $resource->findDescendants(); - $relation[self::DATA] = $related; + $relation[self::RELATIONSHIP_DATA] = $related; } $relationships[self::REL_DESCENDANTS] = $relation; @@ -210,11 +200,11 @@ class StructuralElement extends SchemaProvider private function addImageRelationship(array $relationships, $resource, $includeData) { $relation = [ - self::DATA => $resource->image ?: null, + self::RELATIONSHIP_DATA => $resource->image ?: null, ]; if ($resource->image) { - $relation[self::META] = [ + $relation[self::RELATIONSHIP_META] = [ 'download-url' => $resource->image->getFileType()->getDownloadURL(), ]; } diff --git a/lib/classes/JsonApi/Schemas/Courseware/UserDataField.php b/lib/classes/JsonApi/Schemas/Courseware/UserDataField.php index d42a8007aa914c4eefbb4ce19a5e8485fd08cf6b..810e870ce2c80d4a635d9d937082032e3c210755 100755 --- a/lib/classes/JsonApi/Schemas/Courseware/UserDataField.php +++ b/lib/classes/JsonApi/Schemas/Courseware/UserDataField.php @@ -3,7 +3,8 @@ namespace JsonApi\Schemas\Courseware; use JsonApi\Schemas\SchemaProvider; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class UserDataField extends SchemaProvider { @@ -12,12 +13,10 @@ class UserDataField extends SchemaProvider const REL_BLOCK = 'block'; const REL_USER = 'user'; - protected $resourceType = self::TYPE; - /** * {@inheritdoc} */ - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } @@ -25,7 +24,7 @@ class UserDataField extends SchemaProvider /** * {@inheritdoc} */ - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'payload' => $resource['payload']->getIterator(), @@ -37,26 +36,25 @@ class UserDataField extends SchemaProvider /** * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $relationships[self::REL_BLOCK] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->block) - ->getSelfSubLink($resource->block), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->block), ], - self::DATA => $resource->block, + self::RELATIONSHIP_DATA => $resource->block, ]; $relationships[self::REL_USER] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->user) - ->getSelfSubLink($resource->user), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->user), ], - self::DATA => $resource->user, + self::RELATIONSHIP_DATA => $resource->user, ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/Courseware/UserProgress.php b/lib/classes/JsonApi/Schemas/Courseware/UserProgress.php index 6b8629d1016ddcb611461cb9596105d0dc5221ca..5d6e68a5bfea4d798e114ba6da6d10723a508d74 100755 --- a/lib/classes/JsonApi/Schemas/Courseware/UserProgress.php +++ b/lib/classes/JsonApi/Schemas/Courseware/UserProgress.php @@ -3,7 +3,8 @@ namespace JsonApi\Schemas\Courseware; use JsonApi\Schemas\SchemaProvider; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class UserProgress extends SchemaProvider { @@ -12,12 +13,10 @@ class UserProgress extends SchemaProvider const REL_BLOCK = 'block'; const REL_USER = 'user'; - protected $resourceType = self::TYPE; - /** * {@inheritdoc} */ - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } @@ -25,7 +24,7 @@ class UserProgress extends SchemaProvider /** * {@inheritdoc} */ - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'grade' => (float) $resource['grade'], @@ -37,26 +36,25 @@ class UserProgress extends SchemaProvider /** * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $relationships[self::REL_BLOCK] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->block) - ->getSelfSubLink($resource->block), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->block), ], - self::DATA => $resource->block, + self::RELATIONSHIP_DATA => $resource->block, ]; $relationships[self::REL_USER] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->user) - ->getSelfSubLink($resource->user), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->user), ], - self::DATA => $resource->user, + self::RELATIONSHIP_DATA => $resource->user, ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/FeedbackElement.php b/lib/classes/JsonApi/Schemas/FeedbackElement.php index b8a0f786ce25a99c975134a1e75f26980949a8a6..0709611687203ddb5be9d25a6a9c9aa2de276bf2 100644 --- a/lib/classes/JsonApi/Schemas/FeedbackElement.php +++ b/lib/classes/JsonApi/Schemas/FeedbackElement.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class FeedbackElement extends SchemaProvider { @@ -12,14 +13,14 @@ class FeedbackElement extends SchemaProvider const REL_ENTRIES = 'entries'; const REL_RANGE = 'range'; - protected $resourceType = self::TYPE; - public function getId($resource) + + public function getId($resource): ?string { return (int) $resource->id; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { $attributes = [ 'question' => (string) $resource['question'], @@ -38,7 +39,15 @@ class FeedbackElement extends SchemaProvider /** * @inheritdoc */ - public function getPrimaryMeta($resource) + public function hasResourceMeta($resource): bool + { + return true; + } + + /** + * @inheritdoc + */ + public function getResourceMeta($resource) { return $resource['mode'] === 0 ? null @@ -55,8 +64,11 @@ class FeedbackElement extends SchemaProvider * spezifiziert werden. * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $shouldInclude = function ($key) use ($isPrimary, $includeList) { return $isPrimary && in_array($key, $includeList); }; @@ -76,12 +88,10 @@ class FeedbackElement extends SchemaProvider $userId = $resource['user_id']; $related = $includeData ? \User::find($userId) : \User::build(['id' => $userId], false); $relationships[self::REL_AUTHOR] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($related) - ->getSelfSubLink($related) + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($related) ], - self::DATA => $related + self::RELATIONSHIP_DATA => $related ]; return $relationships; @@ -92,53 +102,47 @@ class FeedbackElement extends SchemaProvider if ($courseId = $resource['course_id']) { $related = $includeData ? \Course::find($courseId) : \Course::build(['id' => $courseId], false); $relationships[self::REL_COURSE] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($related) - ->getSelfSubLink($related) + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($related) ], - self::DATA => $related + self::RELATIONSHIP_DATA => $related ]; } return $relationships; } - private function getEntriesRelationship(array $relationships, \FeedbackElement $resource, $includeData): array + private function getEntriesRelationship(array $relationships, \FeedbackElement $resource, bool $includeData): array { $relationships[self::REL_ENTRIES] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_ENTRIES) ], - self::DATA => $resource->entries + self::RELATIONSHIP_DATA => $resource->entries ]; return $relationships; } - private function getRangeRelationship(array $relationships, \FeedbackElement $resource, $includeData): array + private function getRangeRelationship(array $relationships, \FeedbackElement $resource, bool $includeData): array { $rangeType = $resource['range_type']; - $rangeSchema = null; + $link = null; try { - $rangeSchema = $this->getSchemaContainer()->getSchemaByType($rangeType); - } catch (\InvalidArgumentException $e) { - } - - if ( - isset($rangeSchema) && - is_subclass_of($rangeType, \FeedbackRange::class) && - is_subclass_of($rangeType, \SimpleORMap::class) - ) { - if ($range = $rangeType::find($resource['range_id'])) { - $link = $rangeSchema->getSelfSubLink($range); - - $relationships[self::REL_RANGE] = [ - self::LINKS => [Link::RELATED => $link], - self::DATA => $range - ]; + $link = $this->createLinkToResource($rangeType); + if ( + is_subclass_of($rangeType, \FeedbackRange::class) && + is_subclass_of($rangeType, \SimpleORMap::class) + ) { + if ($range = $rangeType::find($resource['range_id'])) { + $relationships[self::REL_RANGE] = [ + self::RELATIONSHIP_LINKS => [Link::RELATED => $link], + self::RELATIONSHIP_DATA => $range + ]; + } } + } catch (\InvalidArgumentException $e) { } return $relationships; diff --git a/lib/classes/JsonApi/Schemas/FeedbackEntry.php b/lib/classes/JsonApi/Schemas/FeedbackEntry.php index 5583952fdb62bc25c0a1726677c417a790e16f9e..e919c13f5fa02a32d76571a839437323bde5b43b 100644 --- a/lib/classes/JsonApi/Schemas/FeedbackEntry.php +++ b/lib/classes/JsonApi/Schemas/FeedbackEntry.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class FeedbackEntry extends SchemaProvider { @@ -10,20 +11,18 @@ class FeedbackEntry extends SchemaProvider const REL_AUTHOR = 'author'; const REL_FEEDBACK = 'feedback-element'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { $attributes = [ 'comment' => (string) $resource['comment'], - 'rating' => $resource->feedback->mode === 0 ? null : $resource['rating'], + 'rating' => 0 === $resource->feedback->mode ? null : $resource['rating'], 'mkdate' => date('c', $resource['mkdate']), - 'chdate' => date('c', $resource['chdate']) + 'chdate' => date('c', $resource['chdate']), ]; return $attributes; @@ -32,10 +31,14 @@ class FeedbackEntry extends SchemaProvider /** * In dieser Methode können Relationships zu anderen Objekten * spezifiziert werden. + * * {@inheritdoc} */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $shouldInclude = function ($key) use ($isPrimary, $includeList) { return $isPrimary && in_array($key, $includeList); }; @@ -57,12 +60,10 @@ class FeedbackEntry extends SchemaProvider $userId = $resource['user_id']; $related = $includeData ? \User::find($userId) : \User::build(['id' => $userId], false); $relationships[self::REL_AUTHOR] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($related) - ->getSelfSubLink($related) + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($related), ], - self::DATA => $related + self::RELATIONSHIP_DATA => $related, ]; return $relationships; @@ -78,12 +79,10 @@ class FeedbackEntry extends SchemaProvider : \FeedbackElement::build(['id' => $resource->feedback_id], false); $relationships[self::REL_FEEDBACK] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($related) - ->getSelfSubLink($related) + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($related), ], - self::DATA => $related + self::RELATIONSHIP_DATA => $related, ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/File.php b/lib/classes/JsonApi/Schemas/File.php index 45bb2aac8e0e69f1cc5be40c7779821c631a2990..8293b5fc1cd75554c4bc526f0f68844af2b7c075 100644 --- a/lib/classes/JsonApi/Schemas/File.php +++ b/lib/classes/JsonApi/Schemas/File.php @@ -3,7 +3,8 @@ namespace JsonApi\Schemas; use JsonApi\Routes\Files\Authority as FilesAuthority; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class File extends SchemaProvider { @@ -12,19 +13,12 @@ class File extends SchemaProvider const REL_FILE_REFS = 'file-refs'; const REL_OWNER = 'owner'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->getId(); } - public function getInclusionMeta($resource) - { - return $this->getPrimaryMeta($resource); - } - - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { $attributes = [ 'name' => $resource['name'], @@ -36,8 +30,7 @@ class File extends SchemaProvider ]; if ($resource['metadata']['url']) { - $user = $this->getDiContainer()->get('studip-current-user'); - if (FilesAuthority::canUpdateFile($user, $resource)) { + if (FilesAuthority::canUpdateFile($this->currentUser, $resource)) { $attributes['url'] = $resource['metadata']['url']; } } @@ -48,8 +41,11 @@ class File extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; if ($isPrimary) { @@ -65,8 +61,8 @@ class File extends SchemaProvider $refs = $resource->refs; $relationships[self::REL_FILE_REFS] = [ - self::SHOW_SELF => true, - self::DATA => $refs, + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_DATA => $refs, ]; return $relationships; @@ -76,11 +72,10 @@ class File extends SchemaProvider { if ($resource->user_id) { $relationships[self::REL_OWNER] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->owner)->getSelfSubLink($resource->owner), - ], - ]; + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->owner), + ], + ]; } return $relationships; diff --git a/lib/classes/JsonApi/Schemas/FileRef.php b/lib/classes/JsonApi/Schemas/FileRef.php index e92854491cce91c84b33634a7d5465694ec5da1d..5da46f6d475fc566540bc7fb586cb40fc25dd44e 100644 --- a/lib/classes/JsonApi/Schemas/FileRef.php +++ b/lib/classes/JsonApi/Schemas/FileRef.php @@ -2,8 +2,8 @@ namespace JsonApi\Schemas; -use JsonApi\Providers\JsonApiConfig as C; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class FileRef extends SchemaProvider { @@ -18,24 +18,27 @@ class FileRef extends SchemaProvider const META_CONTENT = 'content'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->getId(); } - public function getPrimaryMeta($resource) + /** + * @inheritdoc + */ + public function hasResourceMeta($resource): bool { - $link = $this->getDiContainer()->get(C::JSON_URL_PREFIX) - .$this->getRelationshipRelatedLink($resource, self::META_CONTENT)->getSubHref(); + return true; + } + public function getResourceMeta($resource) + { return [ - 'download-url' => $link, + 'download-url' => $resource->getDownloadURL(), ]; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { $attributes = [ 'name' => $resource['name'], @@ -50,7 +53,7 @@ class FileRef extends SchemaProvider 'mime-type' => $resource->file->mime_type ]; - $user = $this->getDiContainer()->get('studip-current-user'); + $user = $this->currentUser; if ($folder = $resource->getFolderType()) { $filetype = $resource->getFileType(); $attributes = array_merge( @@ -70,8 +73,11 @@ class FileRef extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $relationships = $this->getFeedbackRelationship($relationships, $resource); @@ -94,7 +100,7 @@ class FileRef extends SchemaProvider if ($folder = $resource->getFolderType()) { if ($folder->range_id && $folder->range_type === 'course' && \Feedback::isActivated($folder->range_id)) { $relationships[self::REL_FEEDBACK] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_FEEDBACK) ], ]; @@ -108,11 +114,9 @@ class FileRef extends SchemaProvider { if ($resource->file) { $relationships[self::REL_FILE] = [ - self::DATA => $resource->file, - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->file) - ->getSelfSubLink($resource->file), + self::RELATIONSHIP_DATA => $resource->file, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->file), ], ]; } @@ -123,16 +127,15 @@ class FileRef extends SchemaProvider private function addOwnerRelationship(array $relationships, \FileRef $resource) { $relationships[self::REL_OWNER] = [ - self::META => [ + self::RELATIONSHIP_META => [ 'name' => $resource->getAuthorName(), ], - self::DATA => $resource->owner, + self::RELATIONSHIP_DATA => $resource->owner, ]; if (isset($resource->owner)) { - $relationships[self::REL_OWNER][self::LINKS] = [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->owner)->getSelfSubLink($resource->owner), + $relationships[self::REL_OWNER][self::RELATIONSHIP_LINKS] = [ + Link::RELATED => $this->createLinkToResource($resource->owner), ]; } @@ -144,11 +147,9 @@ class FileRef extends SchemaProvider if ($resource->folder_id) { $folder = $resource->getFolderType(); $relationships[self::REL_PARENT] = [ - self::DATA => $folder, - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($folder) - ->getSelfSubLink($folder), + self::RELATIONSHIP_DATA => $folder, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($folder), ], ]; } @@ -163,11 +164,10 @@ class FileRef extends SchemaProvider try { $rangeType = $folder->range_type; if ($range = $folder->$rangeType) { - $schema = $this->getSchemaContainer()->getSchema($range); $relationships[self::REL_RANGE] = [ - self::DATA => $range, - self::LINKS => [ - Link::RELATED => $schema->getSelfSubLink($range), + self::RELATIONSHIP_DATA => $range, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($range), ], ]; } @@ -182,8 +182,8 @@ class FileRef extends SchemaProvider private function addTermsRelationship(array $relationships, \FileRef $resource) { $relationships[self::REL_TERMS] = [ - self::DATA => $resource->content_terms_of_use_id ? $resource->terms_of_use : null, - self::SHOW_SELF => true, + self::RELATIONSHIP_DATA => $resource->content_terms_of_use_id ? $resource->terms_of_use : null, + self::RELATIONSHIP_LINKS_SELF => true, ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/Folder.php b/lib/classes/JsonApi/Schemas/Folder.php index b28884d9f5df7f68d70e02b66b9348a3a9afa5f3..f2c5608ec4cab1e0dd7469f6a8eb0fcf68ee0728 100644 --- a/lib/classes/JsonApi/Schemas/Folder.php +++ b/lib/classes/JsonApi/Schemas/Folder.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class Folder extends SchemaProvider { @@ -14,16 +15,14 @@ class Folder extends SchemaProvider const REL_FILE_REFS = 'file-refs'; const REL_FOLDERS = 'folders'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->getId(); } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { - $user = $this->getDiContainer()->get('studip-current-user'); + $user = $this->currentUser; $attributes = [ 'folder-type' => $resource->folder_type, @@ -51,8 +50,11 @@ class Folder extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameters) */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; if ($isPrimary) { @@ -71,11 +73,9 @@ class Folder extends SchemaProvider { if ($resource->user_id && $resource->owner) { $relationships[self::REL_OWNER] = [ - self::DATA => $resource->owner, - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->owner) - ->getSelfSubLink($resource->owner), + self::RELATIONSHIP_DATA => $resource->owner, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->owner), ], ]; } @@ -88,11 +88,9 @@ class Folder extends SchemaProvider if ($resource->parent_id) { $parent = $resource->parentfolder->getTypedFolder(); $relationships[self::REL_PARENT] = [ - self::DATA => $parent, - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($parent) - ->getSelfSubLink($parent), + self::RELATIONSHIP_DATA => $parent, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($parent), ], ]; } @@ -117,12 +115,11 @@ class Folder extends SchemaProvider { $rangeType = $resource->range_type; if ($range = $resource->$rangeType) { - $schema = $this->getSchemaContainer()->getSchema($range); return [ - self::DATA => $range, - self::LINKS => [ - Link::RELATED => $schema->getSelfSubLink($range), + self::RELATIONSHIP_DATA => $range, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($range), ], ]; } @@ -133,7 +130,7 @@ class Folder extends SchemaProvider private function getDefaultRangeRelationship($resource) { return [ - self::META => [ + self::RELATIONSHIP_META => [ 'range_id' => $resource->range_id, 'range_type' => $resource->range_type, ], @@ -145,7 +142,7 @@ class Folder extends SchemaProvider if ($resource->range_type === 'course') { if (\Feedback::isActivated($resource->range_id)) { $relationships[self::REL_FEEDBACK] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_FEEDBACK) ], ]; @@ -158,7 +155,7 @@ class Folder extends SchemaProvider private function getFoldersRelationship(array $relationships, $resource) { $relationships[self::REL_FOLDERS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_FOLDERS), ], ]; @@ -169,7 +166,7 @@ class Folder extends SchemaProvider private function getFilesRelationship(array $relationships, $resource) { $relationships[self::REL_FILE_REFS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_FILE_REFS), ], ]; diff --git a/lib/classes/JsonApi/Schemas/ForumCategory.php b/lib/classes/JsonApi/Schemas/ForumCategory.php index f26d70dc44d552646192fa6b474d83064d9933ae..411146498267568323f5413c2527301ab5a24db0 100644 --- a/lib/classes/JsonApi/Schemas/ForumCategory.php +++ b/lib/classes/JsonApi/Schemas/ForumCategory.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; use JsonApi\Models\ForumEntry as Entry; class ForumCategory extends SchemaProvider @@ -11,14 +12,14 @@ class ForumCategory extends SchemaProvider const REL_COURSE = 'course'; const REL_ENTRY = 'entries'; - protected $resourceType = self::TYPE; - public function getId($category) + + public function getId($category): ?string { return $category->id; } - public function getAttributes($category) + public function getAttributes($category, ContextInterface $context): iterable { return [ 'title' => $category->entry_name, @@ -26,8 +27,11 @@ class ForumCategory extends SchemaProvider ]; } - public function getRelationships($category, $isPrimary, array $includeList) + public function getRelationships($category, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; if ($isPrimary) { $relationships = $this->addCourseRelationship($category, $isPrimary, $includeList); @@ -39,14 +43,14 @@ class ForumCategory extends SchemaProvider public function addCourseRelationship($category, $isPrimary, $includeList) { - $link = new Link('/courses/'.$category->seminar_id); $data = $isPrimary && in_array(self::REL_COURSE, $includeList) ? \Course::find($category->seminar_id) : \Course::buildExisting(['id' => $category->seminar_id]); + $link = $this->createLinkToResource($data); $relationships = [ self::REL_COURSE => [ - self::LINKS => [Link::RELATED => $link], - self::DATA => $data, + self::RELATIONSHIP_LINKS => [Link::RELATED => $link], + self::RELATIONSHIP_DATA => $data, ], ]; @@ -59,10 +63,10 @@ class ForumCategory extends SchemaProvider private function addEntryRelationship($category, $isPrimary, $includeList) { $data = Entry::getEntriesFromCat($category); - $link = new Link('/forum-categories/'.($category->id).'/entries'); + $link = $this->getRelationshipRelatedLink($category, self::REL_ENTRY); $relationships[self::REL_ENTRY] = [ - self::DATA => $data, - self::LINKS => [ + self::RELATIONSHIP_DATA => $data, + self::RELATIONSHIP_LINKS => [ Link::RELATED => $link, ], ]; diff --git a/lib/classes/JsonApi/Schemas/ForumEntry.php b/lib/classes/JsonApi/Schemas/ForumEntry.php index 10a6e218be16c5347664b15e4ea66a2c04821652..e99be46e7617e5c1a93071f53c9fa20756283e90 100644 --- a/lib/classes/JsonApi/Schemas/ForumEntry.php +++ b/lib/classes/JsonApi/Schemas/ForumEntry.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Schema\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; use JsonApi\Models\ForumCat; class ForumEntry extends SchemaProvider @@ -11,14 +12,12 @@ class ForumEntry extends SchemaProvider const REL_CAT = 'category'; const REL_ENTRY = 'entries'; - protected $resourceType = self::TYPE; - - public function getId($entry) + public function getId($entry): ?string { return $entry->topic_id; } - public function getAttributes($entry) + public function getAttributes($entry, ContextInterface $context): iterable { return [ 'title' => $entry->name, @@ -30,8 +29,11 @@ class ForumEntry extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function getRelationships($entry, $isPrimary, array $includeList) + public function getRelationships($entry, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; if ($isPrimary) { $relationships = $this->addCategoryRelationship($relationships, $entry, $includeList); @@ -43,16 +45,16 @@ class ForumEntry extends SchemaProvider private function addCategoryRelationship($relationships, $entry, $includeList) { - $cat_link = new Link('/forum-categories/'.($entry->category)->id); + $cat_link = $this->createLinkToResource($entry->category); $cat_data = in_array(self::REL_CAT, $includeList) ? ForumCat::find($entry->category->id) : ForumCat::buildExisting(['id' => $entry->category->id]); $relationships[self::REL_CAT] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $cat_link, ], - self::DATA => $cat_data, + self::RELATIONSHIP_DATA => $cat_data, ]; return $relationships; @@ -64,9 +66,9 @@ class ForumEntry extends SchemaProvider private function addChildEntryRelationship($relationships, $entry, $includeList) { $relationships[self::REL_ENTRY] = [ - self::DATA => $entry->getChildEntries($entry->id), + self::RELATIONSHIP_DATA => $entry->getChildEntries($entry->id), - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($entry, self::REL_ENTRY), ], ]; diff --git a/lib/classes/JsonApi/Schemas/Institute.php b/lib/classes/JsonApi/Schemas/Institute.php index bc3c2e27f44d5080d111bdc520510d2fcacbdf34..0ee99d95f8fb719e235b2ae5e4a46b937be1e97f 100644 --- a/lib/classes/JsonApi/Schemas/Institute.php +++ b/lib/classes/JsonApi/Schemas/Institute.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class Institute extends SchemaProvider { @@ -13,14 +14,12 @@ class Institute extends SchemaProvider const REL_FOLDERS = 'folders'; const REL_STATUS_GROUPS = 'status-groups'; - protected $resourceType = self::TYPE; - - public function getId($institute) + public function getId($institute): ?string { return $institute->id; } - public function getAttributes($institute) + public function getAttributes($institute, ContextInterface $context): iterable { return [ 'name' => $institute['Name'], @@ -37,8 +36,11 @@ class Institute extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $shouldInclude = function ($key) use ($isPrimary, $includeList) { @@ -47,20 +49,20 @@ class Institute extends SchemaProvider $filesLink = $this->getRelationshipRelatedLink($resource, self::REL_FILES); $relationships[self::REL_FILES] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $filesLink, ], ]; $foldersLink = $this->getRelationshipRelatedLink($resource, self::REL_FOLDERS); $relationships[self::REL_FOLDERS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $foldersLink, ], ]; $relationships[self::REL_BLUBBER] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_BLUBBER), ], ]; @@ -80,13 +82,13 @@ class Institute extends SchemaProvider $includeData ) { $relation = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_STATUS_GROUPS), ] ]; if ($includeData) { $related = $resource->status_groups; - $relation[self::DATA] = $related; + $relation[self::RELATIONSHIP_DATA] = $related; } return array_merge($relationships, [self::REL_STATUS_GROUPS => $relation]); diff --git a/lib/classes/JsonApi/Schemas/InstituteMember.php b/lib/classes/JsonApi/Schemas/InstituteMember.php index 190343d2246dd3bfedcd51586b2f4d905bb36710..dbfe9170c6ca812d7fbff0376633ea4c2fa07742 100644 --- a/lib/classes/JsonApi/Schemas/InstituteMember.php +++ b/lib/classes/JsonApi/Schemas/InstituteMember.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class InstituteMember extends SchemaProvider { @@ -10,14 +11,14 @@ class InstituteMember extends SchemaProvider const REL_INSTITUTE = 'institute'; const REL_USER = 'user'; - protected $resourceType = self::TYPE; - public function getId($membership) + + public function getId($membership): ?string { return $membership->id; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { $defaultNull = function ($key) use ($resource) { return $resource->$key ?: null; @@ -40,21 +41,24 @@ class InstituteMember extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = [ self::REL_USER => [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer()->getSchema($resource->user)->getSelfSubLink($resource->user), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->user), ], - self::DATA => $resource->user, + self::RELATIONSHIP_DATA => $resource->user, ], self::REL_INSTITUTE => [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer()->getSchema($resource->institute)->getSelfSubLink($resource->institute), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->institute), ], - self::DATA => $resource->institute, + self::RELATIONSHIP_DATA => $resource->institute, ], ]; diff --git a/lib/classes/JsonApi/Schemas/LibraryFile.php b/lib/classes/JsonApi/Schemas/LibraryFile.php index fa151db94d8e8faacd91466c5786b00028cb0ca8..9073acb91ef8953022efc6e2e0a32e4c6fef37f8 100644 --- a/lib/classes/JsonApi/Schemas/LibraryFile.php +++ b/lib/classes/JsonApi/Schemas/LibraryFile.php @@ -2,8 +2,8 @@ namespace JsonApi\Schemas; -use JsonApi\Providers\JsonApiConfig as C; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class LibraryFile extends SchemaProvider { @@ -18,24 +18,29 @@ class LibraryFile extends SchemaProvider const META_CONTENT = 'content'; - protected $resourceType = self::TYPE; - public function getId($resource) + + public function getId($resource): ?string { return $resource->getId(); } - public function getPrimaryMeta($resource) + /** + * @inheritdoc + */ + public function hasResourceMeta($resource): bool { - $link = $this->getDiContainer()->get(C::JSON_URL_PREFIX) - .$this->getRelationshipRelatedLink($resource, self::META_CONTENT)->getSubHref(); + return true; + } + public function getResourceMeta($resource) + { return [ - 'download-url' => $link, + 'download-url' => $resource->getDownloadURL(), ]; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { $attributes = [ 'name' => $resource->getFilename(), @@ -49,16 +54,16 @@ class LibraryFile extends SchemaProvider 'filesize' => (int) $resource->getSize() ]; - $user = $this->getDiContainer()->get('studip-current-user'); + $userId = $this->currentUser->id; if ($folder = $resource->getFolderType()) { $filetype = $resource->getFileType(); $attributes = array_merge( $attributes, [ - 'is-readable' => $folder->isReadable($user->id), - 'is-downloadable' => $filetype->isDownloadable($user->id), - 'is-editable' => $filetype->isEditable($user->id), - 'is-writable' => $filetype->isWritable($user->id), + 'is-readable' => $folder->isReadable($userId), + 'is-downloadable' => $filetype->isDownloadable($userId), + 'is-editable' => $filetype->isEditable($userId), + 'is-writable' => $filetype->isWritable($userId), ] ); } @@ -69,8 +74,11 @@ class LibraryFile extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $relationships = $this->getFeedbackRelationship($relationships, $resource); @@ -93,7 +101,7 @@ class LibraryFile extends SchemaProvider if ($folder = $resource->getFolderType()) { if ($folder->range_id && $folder->range_type === 'course' && \Feedback::isActivated($folder->range_id)) { $relationships[self::REL_FEEDBACK] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_FEEDBACK) ], ]; @@ -107,11 +115,9 @@ class LibraryFile extends SchemaProvider { if ($resource->file) { $relationships[self::REL_FILE] = [ - self::DATA => $resource->file, - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->file) - ->getSelfSubLink($resource->file), + self::RELATIONSHIP_DATA => $resource->file, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($resource->file), ], ]; } @@ -122,16 +128,15 @@ class LibraryFile extends SchemaProvider private function addOwnerRelationship(array $relationships, \FileRef $resource) { $relationships[self::REL_OWNER] = [ - self::META => [ + self::RELATIONSHIP_META => [ 'name' => $resource->getAuthorName(), ], - self::DATA => $resource->owner, + self::RELATIONSHIP_DATA => $resource->owner, ]; if (isset($resource->owner)) { - $relationships[self::REL_OWNER][self::LINKS] = [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($resource->owner)->getSelfSubLink($resource->owner), + $relationships[self::REL_OWNER][self::RELATIONSHIP_LINKS] = [ + Link::RELATED => $this->createLinkToResource($resource->owner), ]; } @@ -143,11 +148,9 @@ class LibraryFile extends SchemaProvider if ($resource->folder_id) { $folder = $resource->getFolderType(); $relationships[self::REL_PARENT] = [ - self::DATA => $folder, - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($folder) - ->getSelfSubLink($folder), + self::RELATIONSHIP_DATA => $folder, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($folder), ], ]; } @@ -155,18 +158,17 @@ class LibraryFile extends SchemaProvider return $relationships; } - private function addRangeRelationship(array $relationships, \FileRef $resource) + private function addRangeRelationship(array $relationships, \FileRef $resource): array { if ($folder = $resource->getFolderType()) { if ($folder->range_id) { try { $rangeType = $folder->range_type; if ($range = $folder->$rangeType) { - $schema = $this->getSchemaContainer()->getSchema($range); $relationships[self::REL_RANGE] = [ - self::DATA => $range, - self::LINKS => [ - Link::RELATED => $schema->getSelfSubLink($range), + self::RELATIONSHIP_DATA => $range, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($range), ], ]; } @@ -181,8 +183,8 @@ class LibraryFile extends SchemaProvider private function addTermsRelationship(array $relationships, \FileRef $resource) { $relationships[self::REL_TERMS] = [ - self::DATA => $resource->content_terms_of_use_id ? $resource->terms_of_use : null, - self::SHOW_SELF => true, + self::RELATIONSHIP_DATA => $resource->content_terms_of_use_id ? $resource->terms_of_use : null, + self::RELATIONSHIP_LINKS_SELF => true, ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/Message.php b/lib/classes/JsonApi/Schemas/Message.php index c7f053ce8b52ab13cd280b681920876b51ad11c9..211cf85405f93bd11c92fac399d0acffadd1a97d 100644 --- a/lib/classes/JsonApi/Schemas/Message.php +++ b/lib/classes/JsonApi/Schemas/Message.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class Message extends SchemaProvider { @@ -10,16 +11,14 @@ class Message extends SchemaProvider const REL_SENDER = 'sender'; const REL_RECIPIENTS = 'recipients'; - protected $resourceType = self::TYPE; - - public function getId($message) + public function getId($message): ?string { return $message->id; } - public function getAttributes($message) + public function getAttributes($message, ContextInterface $context): iterable { - $user = $this->getDiContainer()->get('studip-current-user'); + $user = $this->currentUser; return [ 'subject' => $message->subject, @@ -31,8 +30,11 @@ class Message extends SchemaProvider ]; } - public function getRelationships($message, $isPrimary, array $includeList) + public function getRelationships($message, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $shouldInclude = function ($key) use ($isPrimary, $includeList) { return $isPrimary && in_array($key, $includeList); }; @@ -54,15 +56,15 @@ class Message extends SchemaProvider $data = null; if ($userId) { $data = $includeData ? \User::find($userId) : \User::build(['id' => $userId], false); - } - $relationships[self::REL_SENDER] = [ - // self::SHOW_SELF => true, - self::LINKS => [ - Link::RELATED => new Link('/users/'.$userId), - ], - self::DATA => $data, - ]; + $relationships[self::REL_SENDER] = [ + // self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($data), + ], + self::RELATIONSHIP_DATA => $data, + ]; + } return $relationships; } @@ -73,11 +75,8 @@ class Message extends SchemaProvider private function getRecipientsRelationship(array $relationships, \Message $message, $includeData) { $relationships[self::REL_RECIPIENTS] = [ - // self::SHOW_SELF => true, - self::LINKS => [ - // Link::RELATED => new Link('/users/'.$userId), - ], - self::DATA => $message->receivers->map(function ($i) { return $i->user; }), + // self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_DATA => $message->receivers->map(function ($i) { return $i->user; }), ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/ScheduleEntry.php b/lib/classes/JsonApi/Schemas/ScheduleEntry.php index 7e38ef6efa132617febaebd95d4e91127c011425..e737e614770d2c286b8da329a4dd4ec979aba3b1 100644 --- a/lib/classes/JsonApi/Schemas/ScheduleEntry.php +++ b/lib/classes/JsonApi/Schemas/ScheduleEntry.php @@ -2,21 +2,22 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Schema\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; class ScheduleEntry extends SchemaProvider { const TYPE = 'schedule-entries'; const REL_OWNER = 'owner'; - protected $resourceType = self::TYPE; - public function getId($entry) + + public function getId($entry): ?string { return $entry->id; } - public function getAttributes($entry) + public function getAttributes($entry, ContextInterface $context): iterable { return [ 'title' => $entry->title, @@ -33,16 +34,19 @@ class ScheduleEntry extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function getRelationships($entry, $isPrimary, array $includeList) + public function getRelationships($entry, ContextInterface $context): iterable { - $link = $this->getSchemaContainer()->getSchema($entry->user)->getSelfSubLink($entry->user); + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + + $link = $this->createLinkToResource($entry->user); $relationships = [ self::REL_OWNER => [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $link, ], - self::DATA => $entry->user, + self::RELATIONSHIP_DATA => $entry->user, ], ]; diff --git a/lib/classes/JsonApi/Schemas/SchemaProvider.php b/lib/classes/JsonApi/Schemas/SchemaProvider.php index b6ebdf32049e4e60f4f18b6f39be3102f6657864..5e158867ccb2e6996e65505dd8b453a668314a21 100644 --- a/lib/classes/JsonApi/Schemas/SchemaProvider.php +++ b/lib/classes/JsonApi/Schemas/SchemaProvider.php @@ -2,38 +2,60 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Contracts\Schema\ContainerInterface; -use Neomerx\JsonApi\Contracts\Schema\SchemaFactoryInterface; +use JsonApi\Errors\InternalServerError; +use Neomerx\JsonApi\Contracts\Factories\FactoryInterface; +use Neomerx\JsonApi\Contracts\Schema\LinkInterface; +use Neomerx\JsonApi\Contracts\Schema\SchemaContainerInterface; +use Neomerx\JsonApi\Schema\BaseSchema; -abstract class SchemaProvider extends \Neomerx\JsonApi\Schema\SchemaProvider +abstract class SchemaProvider extends BaseSchema { - private $schemaContainer; - private $diContainer; + /** @var SchemaContainerInterface */ + protected $schemaContainer; - /** - * @param SchemaFactoryInterface $factory - * @param ContainerInterface $factory - */ - public function __construct(SchemaFactoryInterface $factory, ContainerInterface $schemaContainer) + /** @var ?\User */ + protected $currentUser; + + public function __construct(FactoryInterface $factory, SchemaContainerInterface $schemaContainer, ?\User $user) { + $this->schemaContainer = $schemaContainer; + $this->currentUser = $user; + parent::__construct($factory); + } - $this->schemaContainer = $schemaContainer; - $this->diContainer = $factory->getDependencyInjectionContainer(); + const TYPE = ''; + + public function getType(): string + { + return static::TYPE; } /** - * Return the set schema container. - * - * @return ContainerInterface the schema container + * @inheritdoc */ - protected function getSchemaContainer() + public function isAddSelfLinkInRelationshipByDefault(string $relationshipName): bool { - return $this->schemaContainer; + return false; } - public function getDiContainer() + /** + * @inheritdoc + */ + public function isAddRelatedLinkInRelationshipByDefault(string $relationshipName): bool + { + return false; + } + + /** + * @param mixed $resource + */ + public function createLinkToResource($resource): LinkInterface { - return $this->diContainer; + if (!$this->schemaContainer->hasSchema($resource)) { + throw new InternalServerError('Cannot create links to objects without schema.'); + } + + return $this->schemaContainer->getSchema($resource)->getSelfLink($resource); } } diff --git a/lib/classes/JsonApi/Schemas/SemClass.php b/lib/classes/JsonApi/Schemas/SemClass.php index e7fc448e84c2fe8b5b03b36aae788129b8e62830..694d548e8d35dc2d340434f1e4ad8929d06d604c 100644 --- a/lib/classes/JsonApi/Schemas/SemClass.php +++ b/lib/classes/JsonApi/Schemas/SemClass.php @@ -2,21 +2,20 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class SemClass extends SchemaProvider { const REL_SEM_TYPES = 'sem-types'; const TYPE = 'sem-classes'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource['id']; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'name' => (string) $resource['name'], @@ -32,8 +31,11 @@ class SemClass extends SchemaProvider ]; } - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $shouldInclude = function ($key) use ($isPrimary, $includeList) { @@ -53,14 +55,14 @@ class SemClass extends SchemaProvider private function addSemTypesRelationship(array $relationships, $resource, $includeData) { $relation = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_SEM_TYPES), - ] + ], ]; if ($includeData) { $related = $resource->getSemTypes(); - $relation[self::DATA] = $related; + $relation[self::RELATIONSHIP_DATA] = $related; } $relationships[self::REL_SEM_TYPES] = $relation; diff --git a/lib/classes/JsonApi/Schemas/SemType.php b/lib/classes/JsonApi/Schemas/SemType.php index 0798d7411b7ec62435d9f1e3c7c2ac5f1aa947b8..eb44e93f29a04873283504b782992609a21cd775 100644 --- a/lib/classes/JsonApi/Schemas/SemType.php +++ b/lib/classes/JsonApi/Schemas/SemType.php @@ -2,21 +2,22 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class SemType extends SchemaProvider { const REL_SEM_CLASS = 'sem-class'; const TYPE = 'sem-types'; - protected $resourceType = self::TYPE; - public function getId($resource) + + public function getId($resource): ?string { return $resource['id']; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'name' => $resource['name'], @@ -25,19 +26,20 @@ class SemType extends SchemaProvider ]; } - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; // SemClass $related = $resource->getClass(); $relationships[self::REL_SEM_CLASS] = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($related) - ->getSelfSubLink($related) + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($related) ], - self::DATA => $related, + self::RELATIONSHIP_DATA => $related, ]; return $relationships; diff --git a/lib/classes/JsonApi/Schemas/Semester.php b/lib/classes/JsonApi/Schemas/Semester.php index 10b45bd529d721d559bf20299b0f9c0a50541ec5..f1bca9cba992d4acd24c97755a7378cae9519099 100644 --- a/lib/classes/JsonApi/Schemas/Semester.php +++ b/lib/classes/JsonApi/Schemas/Semester.php @@ -2,18 +2,18 @@ namespace JsonApi\Schemas; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; + class Semester extends SchemaProvider { const TYPE = 'semesters'; - protected $resourceType = self::TYPE; - - public function getId($semester) + public function getId($semester): ?string { return $semester->id; } - public function getAttributes($semester) + public function getAttributes($semester, ContextInterface $context): iterable { return [ 'title' => (string) $semester->name, @@ -26,4 +26,9 @@ class Semester extends SchemaProvider 'visible' => (bool) $semester->visible, ]; } + + public function getRelationships($user, ContextInterface $context): iterable + { + return []; + } } diff --git a/lib/classes/JsonApi/Schemas/SeminarCycleDate.php b/lib/classes/JsonApi/Schemas/SeminarCycleDate.php index a7476f34738c9a2249ac4d37184cd12485c3848d..531b58bfcb4cd850dcf17360629d8379b2f2fbe1 100644 --- a/lib/classes/JsonApi/Schemas/SeminarCycleDate.php +++ b/lib/classes/JsonApi/Schemas/SeminarCycleDate.php @@ -2,21 +2,22 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class SeminarCycleDate extends SchemaProvider { const TYPE = 'seminar-cycle-dates'; const REL_OWNER = 'owner'; - protected $resourceType = self::TYPE; - public function getId($entry) + + public function getId($entry): ?string { return $entry->id; } - public function getAttributes($entry) + public function getAttributes($entry, ContextInterface $context): iterable { $course = \Course::find($entry->seminar_id); @@ -37,14 +38,17 @@ class SeminarCycleDate extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function getRelationships($entry, $isPrimary, array $includeList) + public function getRelationships($entry, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; if ($course = \Course::find($entry->seminar_id)) { - $link = $this->getSchemaContainer()->getSchema($course)->getSelfSubLink($course); + $link = $this->createLinkToResource($course); $relationships = [ - self::REL_OWNER => [self::LINKS => [Link::RELATED => $link], self::DATA => $course], + self::REL_OWNER => [self::RELATIONSHIP_LINKS => [Link::RELATED => $link], self::RELATIONSHIP_DATA => $course], ]; } diff --git a/lib/classes/JsonApi/Schemas/SlimRoute.php b/lib/classes/JsonApi/Schemas/SlimRoute.php index 3e055e5ccdca6913933c4c146b098256e71102e5..cc055942cdf250af92834435337862f28c1bf64e 100644 --- a/lib/classes/JsonApi/Schemas/SlimRoute.php +++ b/lib/classes/JsonApi/Schemas/SlimRoute.php @@ -2,29 +2,35 @@ namespace JsonApi\Schemas; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; + class SlimRoute extends SchemaProvider { const TYPE = 'slim-routes'; - protected $resourceType = self::TYPE; - - public function getId($route) + public function getId($route): ?string { return $route->getIdentifier(); } - public function getAttributes($route) + public function getAttributes($route, ContextInterface $context): iterable { return [ 'methods' => $route->getMethods(), + 'name' => $route->getName(), 'pattern' => $route->getPattern(), ]; } + public function getRelationships($user, ContextInterface $context): iterable + { + return []; + } + /** * @inheritdoc */ - public function getResourceLinks($resource) + public function getLinks($resource): iterable { return []; } diff --git a/lib/classes/JsonApi/Schemas/StatusGroup.php b/lib/classes/JsonApi/Schemas/StatusGroup.php index bb0026caff8c49b422ca8f42bd544c8ff94f71e0..97993e10d5f442448c1b8414c693b287edbc72cf 100644 --- a/lib/classes/JsonApi/Schemas/StatusGroup.php +++ b/lib/classes/JsonApi/Schemas/StatusGroup.php @@ -2,21 +2,20 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class StatusGroup extends SchemaProvider { const REL_RANGE = 'range'; const TYPE = 'status-groups'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->id; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { $stringOrNull = function ($item) { return trim($item) != '' ? (string) $item : null; @@ -42,8 +41,11 @@ class StatusGroup extends SchemaProvider ]; } - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $shouldInclude = function ($key) use ($isPrimary, $includeList) { @@ -68,14 +70,12 @@ class StatusGroup extends SchemaProvider $related = $this->findRange($resource); $relation = [ - self::LINKS => [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($related) - ->getSelfSubLink($related) + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($related) ] ]; if ($includeData) { - $relation[self::DATA] = $related; + $relation[self::RELATIONSHIP_DATA] = $related; } return array_merge($relationships, [self::REL_RANGE => $relation]); diff --git a/lib/classes/JsonApi/Schemas/Studip.php b/lib/classes/JsonApi/Schemas/Studip.php index 1bf3bae706783fc75386ba527df70db5a6523498..a545504331db2c9960a1e27f71ad245e2cf99960 100644 --- a/lib/classes/JsonApi/Schemas/Studip.php +++ b/lib/classes/JsonApi/Schemas/Studip.php @@ -2,13 +2,13 @@ namespace JsonApi\Schemas; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; + class Studip extends SchemaProvider { const TYPE = 'global'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->getId(); } @@ -16,7 +16,12 @@ class Studip extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function getAttributes($news) + public function getAttributes($news, ContextInterface $context): iterable + { + return []; + } + + public function getRelationships($user, ContextInterface $context): iterable { return []; } diff --git a/lib/classes/JsonApi/Schemas/StudipComment.php b/lib/classes/JsonApi/Schemas/StudipComment.php index a02af3161fee59f92996cd60e0f6a105d906d125..7ba2a2d0ba7734ee6cb761d9afe0cb24c0e9a595 100644 --- a/lib/classes/JsonApi/Schemas/StudipComment.php +++ b/lib/classes/JsonApi/Schemas/StudipComment.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class StudipComment extends SchemaProvider { @@ -10,14 +11,12 @@ class StudipComment extends SchemaProvider const REL_AUTHOR = 'author'; const REL_NEWS = 'news'; - protected $resourceType = self::TYPE; - - public function getId($comment) + public function getId($comment): ?string { return $comment->comment_id; } - public function getAttributes($comment) + public function getAttributes($comment, ContextInterface $context): iterable { return [ 'content' => $comment->content, @@ -26,25 +25,31 @@ class StudipComment extends SchemaProvider ]; } - public function getRelationships($comment, $isPrimary, array $includeList) + public function getRelationships($comment, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; if ($isPrimary) { - $relationships[self::REL_AUTHOR] = [ - self::LINKS => [ - Link::RELATED => new Link('/users/'.$comment->user_id), - ], - self::DATA => \User::build(['id' => $comment->user_id], false), - ]; - $relationships[self::REL_NEWS] = [ - self::LINKS => [ - Link::RELATED => new Link('/news/'.$comment->object_id), - ], - self::DATA => in_array(self::REL_NEWS, $includeList) - ? $comment->news : - \StudipNews::build(['id' => $comment->object_id], false), - ]; + if ($author = \User::find($comment->user_id)) { + $relationships[self::REL_AUTHOR] = [ + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($author), + ], + self::RELATIONSHIP_DATA => $author, + ]; + } + + if ($news = \StudipNews::find($comment->object_id)) { + $relationships[self::REL_NEWS] = [ + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($news), + ], + self::RELATIONSHIP_DATA => $news, + ]; + } } return $relationships; diff --git a/lib/classes/JsonApi/Schemas/StudipNews.php b/lib/classes/JsonApi/Schemas/StudipNews.php index 6803fd8d29cf5cfd5f82fa3983015e2e4573a8a3..98b2dc50f7dda8d2a25205a721c79dfc058086c6 100644 --- a/lib/classes/JsonApi/Schemas/StudipNews.php +++ b/lib/classes/JsonApi/Schemas/StudipNews.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class StudipNews extends SchemaProvider { @@ -11,8 +12,6 @@ class StudipNews extends SchemaProvider const REL_COMMENTS = 'comments'; const REL_RANGES = 'ranges'; - protected $resourceType = self::TYPE; - public static function getRangeClasses() { return [ @@ -34,12 +33,12 @@ class StudipNews extends SchemaProvider ]; } - public function getId($news) + public function getId($news): ?string { - return $news->news_id; + return $news->getId(); } - public function getAttributes($news) + public function getAttributes($news, ContextInterface $context): iterable { return [ 'title' => (string) $news->topic, @@ -55,8 +54,11 @@ class StudipNews extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function getRelationships($news, $isPrimary, array $includeList) + public function getRelationships($news, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $relationships = $this->addAuthorRelationship($relationships, $news, $includeList); @@ -72,10 +74,10 @@ class StudipNews extends SchemaProvider ? $news->owner : \User::build(['id' => $news->user_id], false); $relationships[self::REL_AUTHOR] = [ - self::LINKS => [ - Link::RELATED => new Link('/users/'.$news->user_id), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($news->owner), ], - self::DATA => $data, + self::RELATIONSHIP_DATA => $data, ]; return $relationships; @@ -87,9 +89,9 @@ class StudipNews extends SchemaProvider private function addCommentsRelationship($relationships, $news, $includeList) { $relationships[self::REL_COMMENTS] = [ - self::LINKS => [ - Link::RELATED => $this->getRelationshipRelatedLink($news, self::REL_COMMENTS) - ] + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->getRelationshipRelatedLink($news, self::REL_COMMENTS), + ], ]; return $relationships; @@ -98,8 +100,8 @@ class StudipNews extends SchemaProvider private function addRangesRelationship($relationships, $news, $includeList) { $relationships[self::REL_RANGES] = [ - self::SHOW_SELF => true, - self::DATA => $this->prepareRanges($news, $includeList), + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_DATA => $this->prepareRanges($news, $includeList), ]; return $relationships; @@ -112,7 +114,7 @@ class StudipNews extends SchemaProvider return $news->news_ranges->map(function ($range) use ($include) { switch ($range->type) { case 'global': - return $this->getDiContainer()->get('studip-system-object'); + return new \Jsonapi\Models\Studip(); case 'sem': return $include diff --git a/lib/classes/JsonApi/Schemas/StudipProperty.php b/lib/classes/JsonApi/Schemas/StudipProperty.php index d76c47ac54ff2f538d9d5a5f21c8840937ed7546..2f23fa2dd0e9293b2b9268177cad80c5ad9e1145 100644 --- a/lib/classes/JsonApi/Schemas/StudipProperty.php +++ b/lib/classes/JsonApi/Schemas/StudipProperty.php @@ -2,18 +2,18 @@ namespace JsonApi\Schemas; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; + class StudipProperty extends SchemaProvider { const TYPE = 'studip-properties'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource->field; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'description' => $resource->description, @@ -21,10 +21,15 @@ class StudipProperty extends SchemaProvider ]; } + public function getRelationships($resource, ContextInterface $context): iterable + { + return []; + } + /** * @inheritdoc */ - public function getResourceLinks($resource) + public function getLinks($resource): iterable { return []; } diff --git a/lib/classes/JsonApi/Schemas/StudyArea.php b/lib/classes/JsonApi/Schemas/StudyArea.php index 39cfae9898297b0926c26fea7688bb345970f871..6ad289bfc7e8933543e97a96107d22eaa10f5a6a 100644 --- a/lib/classes/JsonApi/Schemas/StudyArea.php +++ b/lib/classes/JsonApi/Schemas/StudyArea.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class StudyArea extends SchemaProvider { @@ -12,14 +13,12 @@ class StudyArea extends SchemaProvider const REL_PARENT = 'parent'; const TYPE = 'study-areas'; - protected $resourceType = self::TYPE; - - public function getId($resource) + public function getId($resource): ?string { return $resource['id']; } - public function getAttributes($resource) + public function getAttributes($resource, ContextInterface $context): iterable { return [ 'name' => (string) $resource['name'], @@ -29,8 +28,11 @@ class StudyArea extends SchemaProvider ]; } - public function getRelationships($resource, $isPrimary, array $includeList) + public function getRelationships($resource, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; $shouldInclude = function ($key) use ($isPrimary, $includeList) { @@ -48,14 +50,14 @@ class StudyArea extends SchemaProvider private function addChildrenRelationship(array $relationships, $resource, $includeData) { $relationships[self::REL_CHILDREN] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_CHILDREN), ], ]; if ($includeData) { $children = $resource->getChildren(); - $relationships[self::REL_CHILDREN][self::DATA] = $children; + $relationships[self::REL_CHILDREN][self::RELATIONSHIP_DATA] = $children; } return $relationships; @@ -64,14 +66,14 @@ class StudyArea extends SchemaProvider private function addCoursesRelationship(array $relationships, $resource, $includeData) { $relationships[self::REL_COURSES] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_COURSES), ], ]; if ($includeData) { $children = $resource->courses; - $relationships[self::REL_COURSES][self::DATA] = $children; + $relationships[self::REL_COURSES][self::RELATIONSHIP_DATA] = $children; } return $relationships; @@ -80,13 +82,13 @@ class StudyArea extends SchemaProvider private function addInstituteRelationship(array $relationships, $resource, $includeData) { $relationships[self::REL_INSTITUTE] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_INSTITUTE), ], ]; if ($includeData) { - $relationships[self::REL_INSTITUTE][self::DATA] = $resource->institute; + $relationships[self::REL_INSTITUTE][self::RELATIONSHIP_DATA] = $resource->institute; } return $relationships; @@ -95,13 +97,13 @@ class StudyArea extends SchemaProvider private function addParentRelationship(array $relationships, $resource, $includeData) { $relationships[self::REL_PARENT] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_PARENT), ], ]; if ($includeData) { - $relationships[self::REL_PARENT][self::DATA] = $resource->getParent(); + $relationships[self::REL_PARENT][self::RELATIONSHIP_DATA] = $resource->getParent(); } return $relationships; diff --git a/lib/classes/JsonApi/Schemas/User.php b/lib/classes/JsonApi/Schemas/User.php index 3bc904ce8ba148a06c9ab4150ad2f19332698553..67e64d56282f8c4a6e867ba1d6b4e6c40bb87fc3 100644 --- a/lib/classes/JsonApi/Schemas/User.php +++ b/lib/classes/JsonApi/Schemas/User.php @@ -2,7 +2,9 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Factories\FactoryInterface; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class User extends SchemaProvider { @@ -23,18 +25,12 @@ class User extends SchemaProvider const REL_OUTBOX = 'outbox'; const REL_SCHEDULE = 'schedule'; - /** - * Hier wird der Typ des Schemas festgelegt. - * {@inheritdoc} - */ - protected $resourceType = self::TYPE; - /** * Diese Method entscheidet über die JSON-API-spezifische ID von * \User-Objekten. * {@inheritdoc} */ - public function getId($user) + public function getId($user): ?string { return $user->id; } @@ -44,7 +40,7 @@ class User extends SchemaProvider * für die Ausgabe vorbereitet werden. * {@inheritdoc} */ - public function getAttributes($user) + public function getAttributes($user, ContextInterface $context): iterable { $attrs = [ 'username' => $user->username, @@ -60,10 +56,10 @@ class User extends SchemaProvider return $attrs + iterator_to_array($this->getProfileAttributes($user)); } - private function getProfileAttributes(\User $user) + private function getProfileAttributes(\User $user): iterable { $visibilities = $this->getVisibilities($user); - $observer = $this->getDiContainer()->get('studip-current-user'); + $observer = $this->currentUser; $fields = [ ['phone', 'privatnr', 'private_phone'], @@ -72,13 +68,15 @@ class User extends SchemaProvider ]; foreach ($fields as list($attr, $field, $vis)) { - $value = ($user[$field] && is_element_visible_for_user($observer->id, $user->id, $visibilities[$vis])) - ? strip_tags((string) $user[$field]) : null; + $value = + $user[$field] && is_element_visible_for_user($observer->id, $user->id, $visibilities[$vis]) + ? strip_tags((string) $user[$field]) + : null; yield $attr => $value; } } - private function getVisibilities(\User $user) + private function getVisibilities(\User $user): array { $visibilities = get_local_visibility_by_id($user->id, 'homepage'); if (is_array(json_decode($visibilities, true))) { @@ -91,26 +89,26 @@ class User extends SchemaProvider /** * @inheritdoc */ - public function getPrimaryMeta($resource) + public function hasResourceMeta($resource): bool { - $avatar = \Avatar::getAvatar($resource->id); - - return [ - 'avatar' => [ - 'small' => $avatar->getURL(\Avatar::SMALL), - 'medium' => $avatar->getURL(\Avatar::MEDIUM), - 'normal' => $avatar->getURL(\Avatar::NORMAL), - 'original' => $avatar->getURL(\Avatar::ORIGINAL) - ] - ]; + return true; } /** - * @inheritdoc + * {@inheritdoc} */ - public function getInclusionMeta($resource) + public function getResourceMeta($resource) { - return $this->getPrimaryMeta($resource); + $avatar = \Avatar::getAvatar($resource->id); + + return [ + 'avatar' => [ + 'small' => $avatar->getURL(\Avatar::SMALL), + 'medium' => $avatar->getURL(\Avatar::MEDIUM), + 'normal' => $avatar->getURL(\Avatar::NORMAL), + 'original' => $avatar->getURL(\Avatar::ORIGINAL), + ], + ]; } /** @@ -119,8 +117,11 @@ class User extends SchemaProvider * eines Nutzers bei Bedarf am \User. * {@inheritdoc} */ - public function getRelationships($user, $isPrimary, array $includeList) + public function getRelationships($user, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $shouldInclude = function ($key) use ($isPrimary, $includeList) { return $isPrimary && in_array($key, $includeList); }; @@ -140,7 +141,7 @@ class User extends SchemaProvider $relationships = $this->getConfigValuesRelationship( $relationships, $user, - $shouldInclude(self::REL_CONTACTS) + $shouldInclude(self::REL_CONFIG_VALUES) ); $relationships = $this->getContactsRelationship( $relationships, @@ -157,46 +158,18 @@ class User extends SchemaProvider $user, $shouldInclude(self::REL_COURSE_MEMBERSHIPS) ); - $relationships = $this->getEventsRelationship( - $relationships, - $user, - $shouldInclude(self::REL_EVENTS) - ); - $relationships = $this->getFileRefsRelationship( - $relationships, - $user, - $shouldInclude(self::REL_FILES) - ); - $relationships = $this->getFoldersRelationship( - $relationships, - $user, - $shouldInclude(self::REL_FOLDERS) - ); - $relationships = $this->getInboxRelationship( - $relationships, - $user, - $shouldInclude(self::REL_INBOX) - ); + $relationships = $this->getEventsRelationship($relationships, $user, $shouldInclude(self::REL_EVENTS)); + $relationships = $this->getFileRefsRelationship($relationships, $user, $shouldInclude(self::REL_FILES)); + $relationships = $this->getFoldersRelationship($relationships, $user, $shouldInclude(self::REL_FOLDERS)); + $relationships = $this->getInboxRelationship($relationships, $user, $shouldInclude(self::REL_INBOX)); $relationships = $this->getInstituteMembershipsRelationship( $relationships, $user, $shouldInclude(self::REL_INSTITUTE_MEMBERSHIPS) ); - $relationships = $this->getNewsRelationship( - $relationships, - $user, - $shouldInclude(self::REL_NEWS) - ); - $relationships = $this->getOutboxRelationship( - $relationships, - $user, - $shouldInclude(self::REL_OUTBOX) - ); - $relationships = $this->getScheduleRelationship( - $relationships, - $user, - $shouldInclude(self::REL_SCHEDULE) - ); + $relationships = $this->getNewsRelationship($relationships, $user, $shouldInclude(self::REL_NEWS)); + $relationships = $this->getOutboxRelationship($relationships, $user, $shouldInclude(self::REL_OUTBOX)); + $relationships = $this->getScheduleRelationship($relationships, $user, $shouldInclude(self::REL_SCHEDULE)); } return $relationships; @@ -205,13 +178,10 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getActivityStreamRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getActivityStreamRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_ACTIVITYSTREAM] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_ACTIVITYSTREAM), ], ]; @@ -222,13 +192,10 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getBlubberRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getBlubberRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_BLUBBER] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_BLUBBER), ], ]; @@ -239,14 +206,11 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getConfigValuesRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getConfigValuesRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_CONFIG_VALUES] = [ - self::SHOW_SELF => true, - self::LINKS => [ + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_CONFIG_VALUES), ], ]; @@ -257,14 +221,11 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getContactsRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getContactsRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_CONTACTS] = [ - self::SHOW_SELF => true, - self::LINKS => [ + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_CONTACTS), ], ]; @@ -275,13 +236,10 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getCoursesRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getCoursesRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_COURSES] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_COURSES), ], ]; @@ -292,13 +250,10 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getCourseMembershipsRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getCourseMembershipsRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_COURSE_MEMBERSHIPS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_COURSE_MEMBERSHIPS), ], ]; @@ -309,13 +264,10 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getFileRefsRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getFileRefsRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_FILES] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_FILES), ], ]; @@ -326,13 +278,10 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getFoldersRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getFoldersRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_FOLDERS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_FOLDERS), ], ]; @@ -343,13 +292,10 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getInboxRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getInboxRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_INBOX] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_INBOX), ], ]; @@ -360,13 +306,10 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getInstituteMembershipsRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getInstituteMembershipsRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_INSTITUTE_MEMBERSHIPS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_INSTITUTE_MEMBERSHIPS), ], ]; @@ -377,13 +320,10 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getEventsRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getEventsRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_EVENTS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_EVENTS), ], ]; @@ -394,13 +334,10 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getNewsRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getNewsRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_NEWS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_NEWS), ], ]; @@ -411,13 +348,10 @@ class User extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getOutboxRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getOutboxRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_OUTBOX] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_OUTBOX), ], ]; @@ -425,17 +359,13 @@ class User extends SchemaProvider return $relationships; } - /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function getScheduleRelationship( - array $relationships, - \User $user, - $includeData - ) { + private function getScheduleRelationship(array $relationships, \User $user, $includeData) + { $relationships[self::REL_SCHEDULE] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($user, self::REL_SCHEDULE), ], ]; diff --git a/lib/classes/JsonApi/Schemas/WikiPage.php b/lib/classes/JsonApi/Schemas/WikiPage.php index d68390fa256f236e07b2bd036220a15a1da6ec0a..30d3bb92bd6919c45063aa0f140bc0777d4690a7 100644 --- a/lib/classes/JsonApi/Schemas/WikiPage.php +++ b/lib/classes/JsonApi/Schemas/WikiPage.php @@ -2,7 +2,8 @@ namespace JsonApi\Schemas; -use Neomerx\JsonApi\Document\Link; +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use Neomerx\JsonApi\Schema\Link; class WikiPage extends SchemaProvider { @@ -15,23 +16,7 @@ class WikiPage extends SchemaProvider const REL_PARENT = 'parent'; const REL_RANGE = 'range'; - protected $resourceType = self::TYPE; - - /** - * {@inheritdoc} - */ - public function getResourceLinks($resource) - { - $url = $this->getDiContainer()->get('router')->pathFor( - 'get-wiki-page', - ['id' => sprintf("%s_%s", $resource->range_id, $resource->keyword)] - ); - $links = [ Link::SELF => $this->createLink($url) ]; - - return $links; - } - - public static function getRangeClasses() + public static function getRangeClasses(): array { return [ 'sem' => \Course::class, @@ -39,7 +24,7 @@ class WikiPage extends SchemaProvider ]; } - public static function getRangeTypes() + public static function getRangeTypes(): array { return [ 'sem' => Course::TYPE, @@ -47,6 +32,11 @@ class WikiPage extends SchemaProvider ]; } + /** + * @param mixed $resource + * + * @return ?string + */ public static function getRangeClass($resource) { $classes = self::getRangeClasses(); @@ -59,6 +49,11 @@ class WikiPage extends SchemaProvider ]; } + /** + * @param mixed $resource + * + * @return ?string + */ public static function getRangeType($resource) { $types = self::getRangeTypes(); @@ -71,7 +66,7 @@ class WikiPage extends SchemaProvider ]; } - public function getId($wiki) + public function getId($wiki): ?string { return sprintf( '%s_%s', @@ -80,7 +75,7 @@ class WikiPage extends SchemaProvider ); } - public function getAttributes($wiki) + public function getAttributes($wiki, ContextInterface $context): iterable { return [ 'keyword' => $wiki->keyword, @@ -90,8 +85,11 @@ class WikiPage extends SchemaProvider ]; } - public function getRelationships($wiki, $isPrimary, array $includeList) + public function getRelationships($wiki, ContextInterface $context): iterable { + $isPrimary = $context->getPosition()->getLevel() === 0; + $includeList = $context->getIncludePaths(); + $relationships = []; if ($isPrimary) { @@ -105,18 +103,16 @@ class WikiPage extends SchemaProvider return $relationships; } - private function addParentRelationship($relationships, $wiki, $includeList) + private function addParentRelationship(array $relationships, \WikiPage $wiki, array $includeList): array { $related = $wiki->parent; $relationships[self::REL_PARENT] = [ - self::SHOW_SELF => true, - self::DATA => $related + self::RELATIONSHIP_LINKS_SELF => true, + self::RELATIONSHIP_DATA => $related ]; if ($related) { - $relationships[self::REL_PARENT][self::LINKS] = [ - Link::RELATED => $this->getSchemaContainer() - ->getSchema($related) - ->getSelfSubLink($related) + $relationships[self::REL_PARENT][self::RELATIONSHIP_LINKS] = [ + Link::RELATED => $this->createLinkToResource($related), ]; } @@ -126,10 +122,10 @@ class WikiPage extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function addChildrenRelationship($relationships, $wiki, $includeList) + private function addChildrenRelationship(array $relationships, \WikiPage $wiki, array $includeList): array { $relationships[self::REL_CHILDREN] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($wiki, self::REL_CHILDREN), ], ]; @@ -140,10 +136,10 @@ class WikiPage extends SchemaProvider /** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function addDescendantsRelationship($relationships, $wiki, $includeList) + private function addDescendantsRelationship(array $relationships, \WikiPage $wiki, array $includeList): array { $relationships[self::REL_DESCENDANTS] = [ - self::LINKS => [ + self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->getRelationshipRelatedLink($wiki, self::REL_DESCENDANTS), ], ]; @@ -151,37 +147,54 @@ class WikiPage extends SchemaProvider return $relationships; } + /** + * @param array $relationships + * @param \WikiPage $wiki + * @param array $includeList + * + * @return array + */ private function addAuthorRelationship($relationships, $wiki, $includeList) { - $data = in_array(self::REL_AUTHOR, $includeList) - ? $wiki->author - : \User::build(['id' => $wiki->user_id], false); - $relationships[self::REL_AUTHOR] = [ - self::LINKS => [ - Link::RELATED => new Link('/users/' . $wiki->user_id), - ], - self::DATA => $data, - ]; + if ($wiki->author) { + $relationships[self::REL_AUTHOR] = [ + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($wiki->author), + ], + self::RELATIONSHIP_DATA => $wiki->author, + ]; + } return $relationships; } + /** + * @param array $relationships + * @param \WikiPage $wiki + * @param array $includeList + * + * @return array + */ private function addRangeRelationship($relationships, $wiki, $includeList) { + $range = $this->prepareRange($wiki); $relationships[self::REL_RANGE] = [ - self::LINKS => [ - Link::RELATED => new Link('/' . self::getRangeType($wiki) . '/' . $wiki->range_id), + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($range), ], - self::DATA => $this->prepareRange($wiki, $includeList), + self::RELATIONSHIP_DATA => $range, ]; return $relationships; } - private function prepareRange($wiki) + private function prepareRange(\WikiPage $wiki): \Range { $class = self::getRangeClass($wiki); - return $class::build(['id' => $wiki->range_id], false); + /** @var \Range $range */ + $range = $class::build(['id' => $wiki->range_id], false); + + return $range; } } diff --git a/lib/classes/JsonApi/dependencies.php b/lib/classes/JsonApi/dependencies.php new file mode 100644 index 0000000000000000000000000000000000000000..904c8170fbf2528954181017d6fa186506800a67 --- /dev/null +++ b/lib/classes/JsonApi/dependencies.php @@ -0,0 +1,62 @@ +<?php + +namespace JsonApi; + +use DI\ContainerBuilder; +use JsonApi\JsonApiIntegration\QueryParser; +use JsonApi\JsonApiIntegration\QueryParserInterface; +use Neomerx\JsonApi\Contracts\Encoder\EncoderInterface; +use Neomerx\JsonApi\Contracts\Factories\FactoryInterface; +use Neomerx\JsonApi\Contracts\Http\Headers\HeaderParametersParserInterface; +use Neomerx\JsonApi\Contracts\Http\Headers\MediaTypeInterface; +use Neomerx\JsonApi\Contracts\Http\ResponsesInterface; +use Neomerx\JsonApi\Contracts\Schema\SchemaContainerInterface; +use Neomerx\JsonApi\Http\Headers\HeaderParametersParser; +use Neomerx\JsonApi\Http\Headers\MediaType; +use Psr\Container\ContainerInterface; + +return function (ContainerBuilder $containerBuilder) { + $containerBuilder->addDefinitions([ + FactoryInterface::class => \DI\create(JsonApiIntegration\Factory::class), + HeaderParametersParserInterface::class => function (FactoryInterface $factory) { + return new HeaderParametersParser($factory); + }, + + SchemaContainerInterface::class => function (ContainerInterface $container, FactoryInterface $factory) { + $schemas = []; + $user = $container->get('studip-current-user'); + foreach ($container->get('json-api-integration-schemas') as $key => $classname) { + $schemas[$key] = function ($schemaContainer) use ($classname, $factory, $user) { + return new $classname($factory, $schemaContainer, $user); + }; + } + + return $factory->createSchemaContainer($schemas); + }, + + EncoderInterface::class => function ( + ContainerInterface $container, + FactoryInterface $factory, + SchemaContainerInterface $schemaContainer + ) { + $urlPrefix = $container->get('json-api-integration-urlPrefix'); + $encoder = $factory->createEncoder($schemaContainer)->withUrlPrefix($urlPrefix); + + return $encoder; + }, + + QueryParserInterface::class => function (ContainerInterface $container) { + $request = $container->get('request'); + $parameters = $request->getQueryParams(); + $queryParser = new QueryParser($parameters); + + return $queryParser; + }, + + ResponsesInterface::class => function (EncoderInterface $encoder) { + $mediaType = new MediaType(MediaTypeInterface::JSON_API_TYPE, MediaTypeInterface::JSON_API_SUB_TYPE); + + return new JsonApiIntegration\Responses($encoder, $mediaType); + }, + ]); +}; diff --git a/lib/classes/JsonApi/middleware.php b/lib/classes/JsonApi/middleware.php new file mode 100644 index 0000000000000000000000000000000000000000..7a318d5b7cad34007153df713b579536ffb2b75d --- /dev/null +++ b/lib/classes/JsonApi/middleware.php @@ -0,0 +1,50 @@ +<?php +namespace JsonApi; + +use Slim\App; + +return function (App $app) { + /** @var \DI\Container */ + $container = $app->getContainer(); + + $app->addBodyParsingMiddleware([ + 'application/vnd.api+json' => function ($input) { + return json_decode($input, true); + }, + ]); + + // set 'request' in container + $app->add(function ($request, $handler) use ($container) { + $container->set('request', $request); + + return $handler->handle($request); + }); + + $app->add(new Middlewares\StudipMockNavigation()); + $app->add(new Middlewares\RemoveTrailingSlashes()); + + // Add Routing Middleware + $app->addRoutingMiddleware(); + + /** @var array|null */ + $corsOrigin = \Config::get()->getValue('JSONAPI_CORS_ORIGIN'); + if (is_array($corsOrigin) && count($corsOrigin)) { + $app->add( + new \Tuupola\Middleware\CorsMiddleware([ + 'origin' => $corsOrigin, + 'methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], + 'headers.allow' => [ + 'Accept', + 'Accept-Encoding', + 'Accept-Language', + 'Authorization', + 'Content-Type', + 'Origin', + ], + 'headers.expose' => ['Etag'], + 'credentials' => true, + 'cache' => 86400, + ]) + ); + } +}; diff --git a/lib/classes/JsonApi/routes.php b/lib/classes/JsonApi/routes.php new file mode 100644 index 0000000000000000000000000000000000000000..c0f5003bf2696ef6909a43385697210191c4dd68 --- /dev/null +++ b/lib/classes/JsonApi/routes.php @@ -0,0 +1,8 @@ +<?php +namespace JsonApi; + +use Slim\App; + +return function (App $app) { + $app->group('/v1', new RouteMap($app)); +}; diff --git a/lib/classes/JsonApi/settings.php b/lib/classes/JsonApi/settings.php new file mode 100644 index 0000000000000000000000000000000000000000..dfb8185089c18c4b57407e078df5fd7ccc103284 --- /dev/null +++ b/lib/classes/JsonApi/settings.php @@ -0,0 +1,55 @@ +<?php + +namespace JsonApi; + +use DI\ContainerBuilder; +use Neomerx\JsonApi\Contracts\Factories\FactoryInterface; +use Neomerx\JsonApi\Contracts\Schema\SchemaContainerInterface; +use Psr\Container\ContainerInterface; + +return function (ContainerBuilder $containerBuilder) { + // Global Settings Object + $containerBuilder->addDefinitions([ + 'studip-current-user' => function () { + if ($user = $GLOBALS['user']) { + return $user->getAuthenticatedUser(); + } + + return null; + }, + 'studip-authenticator' => function () { + return function ($username, $password) { + $check = \StudipAuthAbstract::CheckAuthentication($username, $password); + + if ($check['uid'] && 'nobody' != $check['uid']) { + return \User::find($check['uid']); + } + + return null; + }; + }, + + 'json-api-integration-schemas' => function () { + $schemaMap = new SchemaMap(); + $coreSchemas = $schemaMap(); + + $allSchemas = $coreSchemas; + $pluginSchemas = \PluginEngine::sendMessage(Contracts\JsonApiPlugin::class, 'registerSchemas'); + if (is_array($pluginSchemas) && count($pluginSchemas)) { + foreach ($pluginSchemas as $arrayOfSchemas) { + $allSchemas = array_merge($allSchemas, $arrayOfSchemas); + } + } + + return $allSchemas; + }, + + 'json-api-integration-urlPrefix' => function () { + return rtrim(\URLHelper::getUrl('jsonapi.php/v1'), '/'); + }, + + 'json-api-error-encoder' => function (FactoryInterface $factory) { + return $factory->createEncoder($factory->createSchemaContainer([])); + }, + ]); +}; diff --git a/public/jsonapi.php b/public/jsonapi.php index 6bc83841b6325b5409aa39e39a1963ebc7b6abd4..4b3237082a3dfbab1c4af9659da3c9717f363b1f 100644 --- a/public/jsonapi.php +++ b/public/jsonapi.php @@ -1,30 +1,60 @@ <?php -use JsonApi\AppFactory; -use JsonApi\RouteMap; +use DI\ContainerBuilder; +use Slim\Factory\AppFactory; require '../lib/bootstrap.php'; require '../composer/autoload.php'; -\StudipAutoloader::addAutoloadPath($GLOBALS['STUDIP_BASE_PATH'].DIRECTORY_SEPARATOR.'vendor/oauth-php/library/'); +\StudipAutoloader::addAutoloadPath($GLOBALS['STUDIP_BASE_PATH'] . DIRECTORY_SEPARATOR . 'vendor/oauth-php/library/'); -page_open( - [ - 'sess' => 'Seminar_Session', - 'auth' => 'Seminar_Default_Auth', - 'perm' => 'Seminar_Perm', - 'user' => 'Seminar_User', - ] -); +page_open([ + 'sess' => 'Seminar_Session', + 'auth' => 'Seminar_Default_Auth', + 'perm' => 'Seminar_Perm', + 'user' => 'Seminar_User', +]); // Set base url for URLHelper class URLHelper::setBaseUrl($GLOBALS['CANONICAL_RELATIVE_PATH_STUDIP']); -// create app -$appFactory = new AppFactory(); -$app = $appFactory->makeApp(); +$containerBuilder = new ContainerBuilder(); -// add routes -$app->group('/v1', new RouteMap($app)); +$settings = require 'lib/classes/JsonApi/settings.php'; +$settings($containerBuilder); +$dependencies = require 'lib/classes/JsonApi/dependencies.php'; +$dependencies($containerBuilder); + +// Build PHP_DI Container +$container = $containerBuilder->build(); + +// Instantiate the app +AppFactory::setContainer($container); +$app = AppFactory::create(); +$container->set(\Slim\App::class, $app); + +// Set the base path +$app->setBasePath('/jsonapi.php'); + +// Register middleware +$middleware = require 'lib/classes/JsonApi/middleware.php'; +$middleware($app); + +// Register routes +$routes = require 'lib/classes/JsonApi/routes.php'; +$routes($app); + +// Add Error Middleware +$displayErrors = false; +if (defined('\\Studip\\ENV')) { + $displayErrors = constant('\\Studip\\ENV') === 'development'; +} +$logError = true; +$logErrorDetails = true; + +$errorMiddleware = $app->addErrorMiddleware($displayErrors, $logError, $logErrorDetails); +$errorMiddleware->setDefaultErrorHandler(new \JsonApi\Errors\ErrorHandler($app)); + +// Run app $app->run(); diff --git a/tests/_support/Helper/Jsonapi.php b/tests/_support/Helper/Jsonapi.php index 8cd78f7324f64a34570e94a9a5a2dad5e2b3d4df..e435cad1c7259b3502c9e25f46ab8fe9a41cd56b 100644 --- a/tests/_support/Helper/Jsonapi.php +++ b/tests/_support/Helper/Jsonapi.php @@ -2,12 +2,14 @@ namespace Helper; +use DI\ContainerBuilder; +use JsonApi\Errors\JsonApiErrorRenderer; use JsonApi\Middlewares\Authentication; -use JsonApi\Middlewares\JsonApi as JsonApiMiddleware; use Psr\Http\Message\ResponseInterface; -use Slim\Http\Environment; -use Slim\Http\Request; -use Slim\Http\Response; +use Slim\Factory\AppFactory; +use Slim\Interfaces\ErrorHandlerInterface; +use Slim\Psr7\Factory\ServerRequestFactory; +use Slim\Psr7\Request; use WoohooLabs\Yang\JsonApi\Request\JsonApiRequestBuilder; use WoohooLabs\Yang\JsonApi\Response\JsonApiResponse; @@ -17,9 +19,15 @@ use WoohooLabs\Yang\JsonApi\Response\JsonApiResponse; class Jsonapi extends \Codeception\Module { /** + * @param array $credentials + * @param callable $function + * + * @return mixed + * * @SuppressWarnings(PHPMD.Superglobals) */ - public function withPHPLib($credentials, $function) { + public function withPHPLib($credentials, $function) + { // EVIL HACK $oldPerm = $GLOBALS['perm']; $oldUser = $GLOBALS['user']; @@ -35,112 +43,154 @@ class Jsonapi extends \Codeception\Module return $result; } + /** + * @param array $credentials + * @param string $method + * @param string $pattern + * @param callable $callable + * @param ?string $name + * + * @return \Slim\App + */ public function createApp($credentials, $method, $pattern, $callable, $name = null) { - return $this->createApp0( - $credentials, - function () use ($method, $pattern, $callable, $name) { - $route = $this->map([$method], $pattern, $callable); - if (isset($name)) { - $route->setName($name); - } + return $this->createApp0($credentials, function ($app) use ($method, $pattern, $callable, $name) { + $route = $app->map([strtoupper($method)], $pattern, $callable); + if (isset($name)) { + $route->setName($name); } - ); + }); } + /** + * @param array|null $credentials + * + * @return JsonApiRequestBuilder + */ public function createRequestBuilder($credentials = null) { - $env = []; + $serverParams = []; if ($credentials) { - $env = [ + $serverParams = [ 'PHP_AUTH_USER' => $credentials['username'], 'PHP_AUTH_PW' => $credentials['password'], ]; } + $factory = new ServerRequestFactory(); + $request = $factory->createServerRequest('GET', '', $serverParams); - $requestBuilder = new JsonApiRequestBuilder( - Request::createFromEnvironment( - Environment::mock($env) - ) - ); + $requestBuilder = new JsonApiRequestBuilder($request); - $requestBuilder - ->setProtocolVersion('1.0') - ->setHeader('Accept-Charset', 'utf-8'); + $requestBuilder->setProtocolVersion('1.0')->setHeader('Accept-Charset', 'utf-8'); return $requestBuilder; } + /** + * @param \Slim\App $app + * + * @return JsonApiResponse + */ public function sendMockRequest($app, Request $request) { + /** @var \DI\Container */ $container = $app->getContainer(); - $container['request'] = function ($container) use ($request) { - return $request; - }; - $response = $app($request, new Response()); + $container->set('request', $request); + + $response = $app->handle($request); return new JsonApiResponse($response); } - private function createApp0($credentials, $routerFn) + /** + * @param array|null $credentials + * + * @SuppressWarnings(PHPMD.Superglobals) + */ + private function createApp0($credentials, callable $routerFn): \Slim\App { $app = $this->appFactory(); - $authenticator = function ($username, $password) use ($credentials) { - // must return a \User - if ($username === $credentials['username'] && $password === $credentials['password']) { - return \User::find($credentials['id']); - } - - return null; - }; - $group = $app->group('', $routerFn); if ($credentials) { - $group->add(function ($request, $response, $next) { - $user = $request->getAttribute(Authentication::USER_KEY, null); - - $GLOBALS['auth'] = new \Seminar_Auth(); - $GLOBALS['auth']->auth = array( - 'uid' => $user->user_id, - 'uname' => $user->username, - 'perm' => $user->perms, - ); - - $GLOBALS['user'] = new \Seminar_User($user->user_id); + $authenticator = function ($username, $password) use ($credentials) { + // must return a \User + if ($username === $credentials['username'] && $password === $credentials['password']) { + $user = \User::find($credentials['id']); - $GLOBALS['perm'] = new \Seminar_Perm(); - $GLOBALS['MAIL_VALIDATE_BOX'] = false; + return $user; + } - return $next($request, $response); - })->add(new Authentication($authenticator)); + return null; + }; + + $group + ->add(function ($request, $handler) { + $user = $request->getAttribute(Authentication::USER_KEY, null); + + $GLOBALS['auth'] = new \Seminar_Auth(); + $GLOBALS['auth']->auth = [ + 'uid' => $user->id, + 'uname' => $user->username, + 'perm' => $user->perms, + ]; + $GLOBALS['user'] = new \Seminar_User($user->id); + $GLOBALS['perm'] = new \Seminar_Perm(); + $GLOBALS['MAIL_VALIDATE_BOX'] = false; + $y = new \Seminar_User($user->id); + $x = $y->getAuthenticatedUser(); + + + $dbManager = \DBManager::get(); + $stmt = $dbManager->prepare("SELECT * FROM auth_user_md5 LEFT JOIN user_info USING (user_id) WHERE user_id = ?"); + $stmt->execute([$user->id]); + + return $handler->handle($request); + }) + ->add(new Authentication($authenticator)); } - $group->add(new JsonApiMiddleware($app)); - return $app; } - private function appFactory() + private function appFactory(): \Slim\App { - $factory = new \JsonApi\AppFactory(); + $containerBuilder = new ContainerBuilder(); + + $settings = require 'lib/classes/JsonApi/settings.php'; + $settings($containerBuilder); - return $factory->makeApp(); + $dependencies = require 'lib/classes/JsonApi/dependencies.php'; + $dependencies($containerBuilder); + + // Build PHP_DI Container + $container = $containerBuilder->build(); + + // Instantiate the app + AppFactory::setContainer($container); + $app = AppFactory::create(); + $container->set(\Slim\App::class, $app); + + // Register middleware + $middleware = require 'lib/classes/JsonApi/middleware.php'; + $middleware($app); + + // Add Error Middleware + $errorMiddleware = $app->addErrorMiddleware(true, true, true); + $errorMiddleware->setDefaultErrorHandler(new \JsonApi\Errors\ErrorHandler($app)); + + return $app; } public function storeJsonMD( - $filename, + string $filename, ResponseInterface $response, - $limit = null, - $ellipsis = null - ) { + int $limit = null, + string $ellipsis = null + ): string { $body = "{$response->getBody()}"; - $body = preg_replace( - '!plugins.php\\\\/argonautsplugin!', - 'https:\\/\\/example.com', - $body - ); + $body = preg_replace('!plugins.php\\\\/argonautsplugin!', 'https:\\/\\/example.com', $body); $body = preg_replace('!\\\\/!', '/', $body); $body = preg_replace(['!%5B!', '!%5D!'], ['[', ']'], $body); @@ -156,19 +206,19 @@ class Jsonapi extends \Codeception\Module $jsonPretty = new \Camspiers\JsonPretty\JsonPretty(); $json = $jsonPretty->prettify($jsonBody, JSON_UNESCAPED_SLASHES, ' '); - $dirname = codecept_output_dir().'json-for-slate/'; + $dirname = codecept_output_dir() . 'json-for-slate/'; if (!file_exists($dirname)) { @mkdir($dirname); } if (file_exists($dirname)) { - if (substr($filename, -3) !== '.md') { + if ('.md' !== substr($filename, -3)) { $filename .= '.md'; } - if ($filename[0] !== '_') { - $filename = '_'.$filename; + if ('_' !== $filename[0]) { + $filename = '_' . $filename; } - file_put_contents($dirname.$filename, "```json\n".$json."\n```\n"); + file_put_contents($dirname . $filename, "```json\n" . $json . "\n```\n"); } return $json; diff --git a/tests/_support/Helper/StudipPDO.php b/tests/_support/Helper/StudipPDO.php deleted file mode 100644 index b090f3d333986f9614aa9fec4788bfeb81014a77..0000000000000000000000000000000000000000 --- a/tests/_support/Helper/StudipPDO.php +++ /dev/null @@ -1,649 +0,0 @@ -<?php -/** - * StudipPDO.class.php - Stud.IP PDO class. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Elmar Ludwig - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * - * @category Stud.IP - */ - -/** - * This is a special variant of the standard PDO class that does - * not allow multiple statement execution. - */ -class StudipPDO extends PDO -{ - const PARAM_ARRAY = 100; - const PARAM_COLUMN = 101; - - // Counter for the queries sent to the database - public $query_count = 0; - - /** - * Verifies that the given SQL query only contains a single statement. - * - * @param string SQL statement to check - * - * @throws PDOException when the query contains multiple statements - */ - protected function verify($statement) - { - if (mb_strpos($statement, ';') !== false) { - if (preg_match('/;\s*\S/', self::replaceStrings($statement))) { - throw new PDOException('multiple statement execution not allowed'); - } - } - - // Count executed queries (this is placed here since this is the only - // method that is executed on every call to the database) - $this->query_count += 1; - } - - /** - * Replaces all string literals in the statement with placeholders. - * - * @param string SQL statement - * - * @return string modified SQL statement - */ - protected static function replaceStrings($statement) - { - $count = mb_substr_count($statement, '"') + mb_substr_count($statement, "'") + mb_substr_count($statement, '\\'); - - // use fast preg_replace() variant if possible - if ($count < 1000) { - $result = preg_replace('/"(""|\\\\.|[^\\\\"]+)*"|\'(\'\'|\\\\.|[^\\\\\']+)*\'/s', '?', $statement); - } - - if (!isset($result)) { - // split string into parts at quotes and backslash - $parts = preg_split('/([\\\\"\'])/', $statement, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); - $result = ''; - - for ($part = current($parts); $part !== false; $part = next($parts)) { - // inside quotes, "" is ", '' is ' and \x is x - if ($quote_chr !== null) { - if ($part === $quote_chr) { - $part = next($parts); - - if ($part !== $quote_chr) { - // backtrack and terminate string - prev($parts); - $result .= '?'; - $quote_chr = null; - } - } elseif ($part === '\\') { - // skip next part - next($parts); - } - } elseif ($part === "'" || $part === '"') { - $quote_chr = $part; - $saved_pos = key($parts); - } else { - $result .= $part; - } - } - - if ($quote_chr !== null) { - // unterminated quote: copy to end of string - $result .= implode(array_slice($parts, $saved_pos)); - } - } - - return $result; - } - - /** - * Quotes the given value in a form appropriate for the type. - * If no explicit type is given, the value's PHP type is used. - * - * @param string PHP value to quote - * @param int parameter type (e.g. PDO::PARAM_STR) - * - * @return string quoted SQL string - */ - public function quote($value, $type = null) - { - if (!isset($type)) { - if (is_null($value)) { - $type = PDO::PARAM_NULL; - } elseif (is_bool($value)) { - $type = PDO::PARAM_BOOL; - } elseif (is_int($value)) { - $type = PDO::PARAM_INT; - } elseif (is_array($value)) { - $type = self::PARAM_ARRAY; - } else { - $type = PDO::PARAM_STR; - } - } - - switch ($type) { - case PDO::PARAM_NULL: - return 'NULL'; - case PDO::PARAM_BOOL: - return $value ? '1' : '0'; - case PDO::PARAM_INT: - return (int) $value; - case self::PARAM_ARRAY: - return is_array($value) && count($value) ? join(',', array_map(array($this, 'quote'), $value)) : 'NULL'; - case self::PARAM_COLUMN: - return preg_replace('/\\W/', '', $value); - default: - return parent::quote($value); - } - } - - /** - * Executes an SQL statement and returns the number of affected rows. - * - * @param string SQL statement - * - * @return int number of affected rows - */ - public function exec($statement) - { - $this->verify($statement); - - return parent::exec($statement); - } - - /** - * Executes an SQL statement, returning a result set as a statement object. - * - * @param string SQL statement - * @param int fetch mode (optional) - * @param mixed fetch mode parameter (see PDOStatement::setFetchMode) - * @param mixed fetch mode parameter (see PDOStatement::setFetchMode) - * - * @return object PDOStatement object - */ - public function query($statement, $mode = null, $arg1 = null, $arg2 = null) - { - $this->verify($statement); - - if (isset($mode)) { - $stmt = parent::query($statement, $mode, $arg1, $arg2); - } else { - $stmt = parent::query($statement); - } - - $studip_stmt = new StudipPDOStatement($this, $statement, array()); - $studip_stmt->setStatement($stmt); - - return $studip_stmt; - } - - /** - * Prepares a statement for execution and returns a statement object. - * - * @param string SQL statement - * - * @return object PDOStatement object - */ - public function prepare($statement, $driver_options = array()) - { - $this->verify($statement); - - return new StudipPDOStatement($this, $statement, $driver_options); - } - - /** - * This method is intended only for use by the StudipPDOStatement class. - * - * @param string SQL statement - * - * @return object PDOStatement object - */ - public function prepareStatement($statement, $driver_options = array()) - { - return parent::prepare($statement, $driver_options); - } - - /** - * Executes sql statement with given parameters, - * returns number of affected rows, use only for INSERT,UPDATE etc. - * - * @param string $statement SQL statement to execute - * @param array $input_parameters parameters for statement - * - * @return int number of affected rows - */ - public function execute($statement, $input_parameters = null) - { - $st = $this->prepare($statement); - $ok = $st->execute($input_parameters); - if ($ok === true) { - return $st->rowCount(); - } - } - - /** - * Executes sql statement with given parameters, and fetch results - * as sequential array, each row as associative array - * optionally apply given callable on each row, with current row and key as parameter. - * - * @param string $statement SQL statement to execute - * @param array $input_parameters parameters for statement - * @param callable $callable callable to be applied to each of the rows - * - * @return array result set as array of assoc arrays - */ - public function fetchAll($statement, $input_parameters = null, $callable = null) - { - $st = $this->prepare($statement); - $st->execute($input_parameters); - if (is_callable($callable)) { - $data = array(); - $st->setFetchMode(PDO::FETCH_ASSOC); - foreach ($st as $key => $row) { - $data[$key] = call_user_func($callable, $row, $key); - } - } else { - $data = $st->fetchAll(PDO::FETCH_ASSOC); - } - - return $data; - } - - /** - * Executes sql statement with given parameters, and fetch only - * the values from first column as sequential array - * optionally apply given callable on each row, with current value and key as parameter. - * - * @see StudipPDOStatement::fetchFirst() - * - * @param string $statement SQL statement to execute - * @param array $input_parameters parameters for statement - * @param callable $callable callable to be applied to each of the rows - * - * @return array result set - */ - public function fetchFirst($statement, $input_parameters = null, $callable = null) - { - $st = $this->prepare($statement); - $st->execute($input_parameters); - $data = $st->fetchFirst(); - if (is_callable($callable)) { - foreach ($data as $key => $row) { - $data[$key] = call_user_func($callable, $row, $key); - } - } - - return $data; - } - - /** - * Executes sql statement with given parameters, and fetch results - * as associative array, first columns value is used as a key, the others are grouped - * optionally apply given callable on each grouped row, with current row and key as parameter - * if no callable is given, 'current' is used, to return the first entry of the grouped row. - * - * @see StudipPDOStatement::fetchGrouped() - * - * @param string $statement SQL statement to execute - * @param array $input_parameters parameters for statement - * @param callable $callable callable to be applied to each of the rows - * - * @return array result set - */ - public function fetchGrouped($statement, $input_parameters = null, $callable = null) - { - $st = $this->prepare($statement); - $st->execute($input_parameters); - $data = $st->fetchGrouped(PDO::FETCH_ASSOC, is_null($callable) ? 'current' : null); - if (is_callable($callable)) { - foreach ($data as $key => $row) { - $data[$key] = call_user_func($callable, $row, $key); - } - } - - return $data; - } - - /** - * Executes sql statement with given parameters, and fetch results - * as associative array, first columns value is used as a key, the other one is grouped - * use only when selecting 2 columns - * optionally apply given callable on each grouped row, with current row and key as parameter. - * - * @see StudipPDOStatement::fetchGroupedPairs() - * - * @param string $statement SQL statement to execute - * @param array $input_parameters parameters for statement - * @param callable $callable callable to be applied to each of the rows - * - * @return array result set - */ - public function fetchGroupedPairs($statement, $input_parameters = null, $callable = null) - { - $st = $this->prepare($statement); - $st->execute($input_parameters); - $data = $st->fetchGroupedPairs(); - if (is_callable($callable)) { - foreach ($data as $key => $row) { - $data[$key] = call_user_func($callable, $row, $key); - } - } - - return $data; - } - - /** - * Executes sql statement with given parameters, and fetch results - * as associative array, first columns value is used as a key, the other one as the value - * use only when selecting 2 columns - * optionally apply given callable on each grouped row, with current row and key as parameter. - * - * @see StudipPDOStatement::fetchGroupedPairs() - * - * @param string $statement SQL statement to execute - * @param array $input_parameters parameters for statement - * @param callable $callable callable to be applied to each of the rows - * - * @return array result set - */ - public function fetchPairs($statement, $input_parameters = null, $callable = null) - { - $st = $this->prepare($statement); - $st->execute($input_parameters); - $data = $st->fetchPairs(); - if (is_callable($callable)) { - foreach ($data as $key => $row) { - $data[$key] = call_user_func($callable, $row, $key); - } - } - - return $data; - } - - /** - * Executes sql statement with given parameters, and fetch only the first row - * as associative array. - * - * @see StudipPDOStatement::fetchOne() - * - * @param string $statement SQL statement to execute - * @param array $input_parameters parameters for statement - * - * @return array first row of result set - */ - public function fetchOne($statement, $input_parameters = null) - { - $st = $this->prepare($statement); - $st->execute($input_parameters); - - return $st->fetchOne(); - } - - /** - * Executes sql statement with given parameters, and fetch only the value of one column - * third param denotes the column, zero indexed. - * - * @param string $statement SQL statement to execute - * @param array $input_parameters parameters for statement - * @param int $column number of column to fetch - * - * @return string value of chosen column - */ - public function fetchColumn($statement, $input_parameters = null, $column = 0) - { - $st = $this->prepare($statement); - $st->execute($input_parameters); - - return $st->fetchColumn($column); - } -} - -/** - * This is a "fake" PDOStatement implementation that behaves mostly like - * a real statement object, but has some additional features:. - * - * - Parameters passed to execute() are quoted according to their PHP type. - * - A PHP NULL value will result in an actual SQL NULL value in the query. - * - Array types are supported for all placeholders ("WHERE value IN (?)"). - * - Positional and named parameters can be mixed in the same query. - */ -class StudipPDOStatement implements IteratorAggregate -{ - protected $db; - protected $query; - protected $options; - protected $columns; - protected $params; - protected $count; - protected $stmt; - - /** - * Initializes a new StudipPDOStatement instance. - */ - public function __construct($db, $query, $options) - { - $this->db = $db; - $this->query = $query; - $this->options = $options; - $this->params = array(); - } - - /** - * Injects a PDOStatement. - */ - public function setStatement(PDOStatement $statement) - { - $this->stmt = $statement; - } - - /** - * Arranges to have a particular variable bound to a given column in - * the result-set from a query. Each call to fetch() or fetchAll() - * will update all the variables that are bound to columns. - */ - public function bindColumn($column, &$param/*, ...*/) - { - $args = func_get_args(); - $args[1] = &$param; - $this->columns[] = $args; - - return true; - } - - /** - * Binds a PHP variable to a corresponding named or question mark place- - * holder in the SQL statement that was used to prepare the statement. - * Unlike bindValue(), the variable is bound as a reference and will - * only be evaluated at the time that execute() is called. - */ - public function bindParam($parameter, &$variable, $data_type = null) - { - if (is_string($parameter) && $parameter[0] !== ':') { - $parameter = ':'.$parameter; - } - - $this->params[$parameter] = array('value' => &$variable, 'type' => $data_type); - - return true; - } - - /** - * Binds a value to a corresponding named or question mark placeholder - * in the SQL statement that was used to prepare the statement. - */ - public function bindValue($parameter, $value, $data_type = null) - { - if (is_string($parameter) && $parameter[0] !== ':') { - $parameter = ':'.$parameter; - } - - $this->params[$parameter] = array('value' => $value, 'type' => $data_type); - - return true; - } - - /** - * Forwards all unknown methods to the actual statement object. - */ - public function __call($name, array $arguments) - { - $callable = array($this->stmt, $name); - if (!is_callable($callable)) { - throw new BadMethodCallException(); - } - - return call_user_func_array($callable, $arguments); - } - - /** - * Forwards all Iterator methods to the actual statement object. - */ - public function getIterator() - { - return $this->stmt; - } - - /** - * Executes the prepared statement and returns a PDOStatement object. - */ - public function execute($input_parameters = null) - { - // bind additional parameters from execute() - if (isset($input_parameters)) { - foreach ($input_parameters as $key => $value) { - $this->bindValue(is_int($key) ? $key + 1 : $key, $value, null); - } - } - - // emulate prepared statement if necessary - foreach ($this->params as $key => $param) { - if ($param['type'] === StudipPDO::PARAM_ARRAY || - $param['type'] === StudipPDO::PARAM_COLUMN || - $param['type'] === null && !is_string($param['value'])) { - $emulate_prepare = true; - break; - } - } - - // build the actual query string and prepared statement - if ($emulate_prepare) { - $this->count = 1; - $query = preg_replace_callback('/\?|:\w+/', array($this, 'replaceParam'), $this->query); - } else { - $query = $this->query; - } - - $this->stmt = $this->db->prepareStatement($query, $this->options); - - // bind query parameters on the actual statement - if (!$emulate_prepare) { - foreach ($this->params as $key => $param) { - $this->stmt->bindValue($key, $param['value'], $param['type']); - } - } - - // set up column bindings on the actual statement - if (isset($this->columns)) { - foreach ($this->columns as $args) { - call_user_func_array(array($this->stmt, 'bindColumn'), $args); - } - } - - return $this->stmt->execute(); - } - - /** - * Replaces a placeholder with the corresponding parameter value. - * Throws an exception if there is no corresponding value. - */ - protected function replaceParam($matches) - { - $name = $matches[0]; - - if ($name == '?') { - $key = $this->count++; - } else { - $key = $name; - } - - if (!isset($this->params[$key])) { - throw new PDOException('missing parameter in query: '.$key); - } - - return $this->db->quote($this->params[$key]['value'], $this->params[$key]['type']); - } - - /** - * Returns the result set rows as a grouped associative array. The first field - * of each row is used as the array's keys. - * optionally apply given callable on each grouped row to aggregate results - * if no callable is given, 'current' is used, to return the first entry of the grouped row. - * - * @param int $fetch_style Either PDO::FETCH_ASSOC or PDO::FETCH_COLUMN - * @param callable $group_func function to aggregate grouped rows - * - * @return array grouped result set - */ - public function fetchGrouped($fetch_style = PDO::FETCH_ASSOC, $group_func = 'current') - { - if (!($fetch_style & (PDO::FETCH_ASSOC | PDO::FETCH_COLUMN))) { - throw new PDOException('Fetch style not supported, try FETCH_ASSOC or FETCH_COLUMN'); - } - - $fetch_style |= PDO::FETCH_GROUP; - $rows = $this->fetchAll($fetch_style); - - return is_callable($group_func) ? array_map($group_func, $rows) : $rows; - } - - /** - * Returns the result set rows as a grouped associative array. The first field - * of each row is used as the array's keys, the other one is grouped - * use only when selecting 2 columns - * optionally apply given callable on each grouped row to aggregate results. - * - * @param callable $group_func function to aggregate grouped rows - * - * @return array grouped result set - */ - public function fetchGroupedPairs($group_func = null) - { - return $this->fetchGrouped(PDO::FETCH_COLUMN, $group_func); - } - - /** - * Returns result rows as associative array, first colum as key, - * second as value. Use only when selecting 2 columns. - * - * @return array result set - */ - public function fetchPairs() - { - return $this->fetchAll(PDO::FETCH_KEY_PAIR); - } - - /** - * Returns sequential array with values from first colum. - * - * @return array first row result set - */ - public function fetchFirst() - { - return $this->fetchAll(PDO::FETCH_COLUMN); - } - - /** - * Returns only first row of result set as associative array. - * - * @return array first row result set - */ - public function fetchOne() - { - $data = $this->fetch(PDO::FETCH_ASSOC); - - return $data ?: array(); - } -} diff --git a/tests/_support/_generated/JsonapiTesterActions.php b/tests/_support/_generated/JsonapiTesterActions.php index e4f4bde5a6d525277a2fb121afcdbee1cc83967c..9faaeec96dbbe35f2edf4acde9118df8e197d724 100644 --- a/tests/_support/_generated/JsonapiTesterActions.php +++ b/tests/_support/_generated/JsonapiTesterActions.php @@ -2096,6 +2096,11 @@ trait JsonapiTesterActions /** * [!] Method is generated. Documentation taken from corresponding module. * + * @param array $credentials + * @param callable $function + * + * @return mixed + * * @SuppressWarnings(PHPMD.Superglobals) * @see \Helper\Jsonapi::withPHPLib() */ @@ -2107,7 +2112,13 @@ trait JsonapiTesterActions /** * [!] Method is generated. Documentation taken from corresponding module. * + * @param array $credentials + * @param string $method + * @param string $pattern + * @param callable $callable + * @param ?string $name * + * @return \Slim\App * @see \Helper\Jsonapi::createApp() */ public function createApp($credentials, $method, $pattern, $callable, $name = NULL) { @@ -2118,7 +2129,9 @@ trait JsonapiTesterActions /** * [!] Method is generated. Documentation taken from corresponding module. * + * @param array|null $credentials * + * @return JsonApiRequestBuilder * @see \Helper\Jsonapi::createRequestBuilder() */ public function createRequestBuilder($credentials = NULL) { @@ -2129,10 +2142,12 @@ trait JsonapiTesterActions /** * [!] Method is generated. Documentation taken from corresponding module. * + * @param \Slim\App $app * + * @return JsonApiResponse * @see \Helper\Jsonapi::sendMockRequest() */ - public function sendMockRequest($app, \Slim\Http\Request $request) { + public function sendMockRequest($app, \Slim\Psr7\Request $request) { return $this->getScenario()->runStep(new \Codeception\Step\Action('sendMockRequest', func_get_args())); } @@ -2143,7 +2158,7 @@ trait JsonapiTesterActions * * @see \Helper\Jsonapi::storeJsonMD() */ - public function storeJsonMD($filename, \Psr\Http\Message\ResponseInterface $response, $limit = NULL, $ellipsis = NULL) { + public function storeJsonMD(string $filename, \Psr\Http\Message\ResponseInterface $response, ?int $limit = NULL, ?string $ellipsis = NULL): string { return $this->getScenario()->runStep(new \Codeception\Step\Action('storeJsonMD', func_get_args())); } } diff --git a/tests/jsonapi/BlubberCommentsUpdateTest.php b/tests/jsonapi/BlubberCommentsUpdateTest.php index 7ee569da2877aa1bdb5b97575484bc2183ab5b55..d9f4a1e705baaf80ea7a3fb3cc3a7aa9e6425983 100644 --- a/tests/jsonapi/BlubberCommentsUpdateTest.php +++ b/tests/jsonapi/BlubberCommentsUpdateTest.php @@ -50,13 +50,9 @@ class BlubberCommentsUpdateTest extends \Codeception\Test\Unit $comment = $this->createBlubberComment($credentialsAutor, $thread, 'Autolykos knows him.'); $this->tester->assertEquals($num + 1, \BlubberComment::countBySQL('1')); - $this->tester->expectThrowable(\JsonApi\Errors\AuthorizationFailedException::class, function () use ( - $credentialsDozent, - $comment - ) { - $content = 'Who knows Erginos?'; - $this->updateBlubberCommentJSONAPI($credentialsDozent, $comment, $content); - }); + $content = 'Who knows Erginos?'; + $response = $this->updateBlubberCommentJSONAPI($credentialsDozent, $comment, $content); + $this->tester->assertSame(403, $response->getStatusCode()); } public function testUpdateOtherCommentSuccess() diff --git a/tests/jsonapi/BlubberThreadsCreateTest.php b/tests/jsonapi/BlubberThreadsCreateTest.php index 9bcbf41626345534c5b7576195fdaab1c8676527..4b275d54249107b3d62fbbb459e792610dbc8b6f 100644 --- a/tests/jsonapi/BlubberThreadsCreateTest.php +++ b/tests/jsonapi/BlubberThreadsCreateTest.php @@ -69,14 +69,14 @@ class BlubberThreadsCreateTest extends \Codeception\Test\Unit // given $credentials = $this->tester->getCredentialsForTestAutor(); - $this->expectException(JsonApi\Errors\BadRequestException::class); - $this->createThread($credentials, 'course'); + $response = $this->createThread($credentials, 'course'); + $this->tester->assertSame(400, $response->getStatusCode()); - $this->expectException(JsonApi\Errors\BadRequestException::class); - $this->createThread($credentials, 'institute'); + $response = $this->createThread($credentials, 'institute'); + $this->tester->assertSame(400, $response->getStatusCode()); - $this->expectException(JsonApi\Errors\BadRequestException::class); - $this->createThread($credentials, 'public'); + $response = $this->createThread($credentials, 'public'); + $this->tester->assertSame(400, $response->getStatusCode()); } diff --git a/tests/jsonapi/BlubberThreadsIndexTest.php b/tests/jsonapi/BlubberThreadsIndexTest.php index 304f6b1d75f5dc4887699debd26923c719792206..ea665ab108221849bbd3accf4d88e21d588bb869 100644 --- a/tests/jsonapi/BlubberThreadsIndexTest.php +++ b/tests/jsonapi/BlubberThreadsIndexTest.php @@ -118,10 +118,9 @@ class BlubberThreadsIndexTest extends \Codeception\Test\Unit // given $credentials = $this->tester->getCredentialsForTestAutor(); - $this->tester->expectThrowable(RecordNotFoundException::class, function () use ($credentials) { - $courseId = 'missing'; - $this->fetchCourseThreads($credentials, $courseId); - }); + $courseId = 'missing'; + $response = $this->fetchCourseThreads($credentials, $courseId); + $this->tester->assertSame(404, $response->getStatusCode()); } public function testIndexAllThreadsOfAnInstitute() @@ -151,10 +150,9 @@ class BlubberThreadsIndexTest extends \Codeception\Test\Unit // given $credentials = $this->tester->getCredentialsForTestAutor(); - $this->tester->expectThrowable(RecordNotFoundException::class, function () use ($credentials) { - $instituteId = 'missing'; - $this->fetchInstituteThreads($credentials, $instituteId); - }); + $instituteId = 'missing'; + $response = $this->fetchInstituteThreads($credentials, $instituteId); + $this->tester->assertSame(404, $response->getStatusCode()); } public function testIndexAllThreadsWithSinceFilter() @@ -265,7 +263,8 @@ class BlubberThreadsIndexTest extends \Codeception\Test\Unit ); } - private function fetchCourseThreads(array $credentials, string $courseId, array $filters = []) + private function fetchCourseThreads + (array $credentials, string $courseId, array $filters = []) { $requestBuilder = $this->tester ->createRequestBuilder($credentials) diff --git a/tests/jsonapi/FileRefsCreateTest.php b/tests/jsonapi/FileRefsCreateTest.php index 1e3c5b535a80edd12ce9af5dae847fdb996c74ea..d58e1813c2efdc6cce2c2f6f76c7cbc7bf3be22b 100644 --- a/tests/jsonapi/FileRefsCreateTest.php +++ b/tests/jsonapi/FileRefsCreateTest.php @@ -1,10 +1,10 @@ -<?php - +><?php use JsonApi\Errors\RecordNotFoundException; use JsonApi\Errors\UnprocessableEntityException; -use JsonApi\Routes\Files\FileRefsCreate; +use JsonApi\Routes\Files\NegotiateFileRefsCreate as FileRefsCreate; use JsonApi\Schemas\ContentTermsOfUse; use JsonApi\Schemas\FileRef; +use Slim\Psr7\Factory\ServerRequestFactory; require_once 'FilesTestHelper.php'; @@ -36,13 +36,7 @@ class FileRefsCreateTest extends \Codeception\Test\Unit $name = 'filename.jpg'; $description = 'a description'; - $response = $this->sendCreateFileRefInFolder( - $credentials, - $folder, - $name, - $description, - $license - ); + $response = $this->sendCreateFileRefInFolder($credentials, $folder, $name, $description, $license); $this->assertFileRefCreated($response, $name, $description, $license); } @@ -56,18 +50,8 @@ class FileRefsCreateTest extends \Codeception\Test\Unit $name = 'filename.jpg'; $description = 'a description'; - $this->tester->expectThrowable( - RecordNotFoundException::class, - function () use ($credentials, $missingFolder, $name, $description, $license) { - $this->sendCreateFileRefInFolder( - $credentials, - $missingFolder, - $name, - $description, - $license - ); - } - ); + $response = $this->sendCreateFileRefInFolder($credentials, $missingFolder, $name, $description, $license); + $this->tester->assertSame(404, $response->getStatusCode()); } public function testShouldFailOnEmptyName() @@ -80,18 +64,8 @@ class FileRefsCreateTest extends \Codeception\Test\Unit $name = ''; $description = 'a description'; - $this->tester->expectThrowable( - UnprocessableEntityException::class, - function () use ($credentials, $folder, $name, $description, $license) { - $this->sendCreateFileRefInFolder( - $credentials, - $folder, - $name, - $description, - $license - ); - } - ); + $response = $this->sendCreateFileRefInFolder($credentials, $folder, $name, $description, $license); + $this->tester->assertSame(422, $response->getStatusCode()); } public function testShouldFailOnMissingLicense() @@ -103,18 +77,8 @@ class FileRefsCreateTest extends \Codeception\Test\Unit $name = 'a-real-filename.gif'; $description = 'a description'; - $this->tester->expectThrowable( - UnprocessableEntityException::class, - function () use ($credentials, $folder, $name, $description) { - $this->sendCreateFileRefInFolder( - $credentials, - $folder, - $name, - $description, - null - ); - } - ); + $response = $this->sendCreateFileRefInFolder($credentials, $folder, $name, $description, null); + $this->tester->assertSame(422, $response->getStatusCode()); } public function testShouldCreateLinkIfSameUser() @@ -133,8 +97,8 @@ class FileRefsCreateTest extends \Codeception\Test\Unit $credentials, $folder, $file, - $name = "another-name.jpg", - $description = "another description", + $name = 'another-name.jpg', + $description = 'another description', $license ); @@ -162,8 +126,8 @@ class FileRefsCreateTest extends \Codeception\Test\Unit $credentialsAutor, $folder, $file, - $name = "another-name.jpg", - $description = "another description", + $name = 'another-name.jpg', + $description = 'another description', $license ); @@ -174,20 +138,47 @@ class FileRefsCreateTest extends \Codeception\Test\Unit $this->assertFileRefCreated($response, $name, $description, $license); } + public function testShouldCreateFileRefByUpload() + { + $credentials = $this->tester->getCredentialsForTestDozent(); + $courseId = 'a07535cf2f8a72df33c12ddfa4b53dde'; + $folder = $this->prepareTopFolder($credentials, $courseId); + $license = $this->getSampleLicense(); + + $name = 'tiny.gif'; + $filename = __DIR__ . '/' . $name; + $description = 'a description'; + $content = base64_decode('R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='); + if (!file_exists($filename)) { + file_put_contents($filename, $content); + } + $this->tester->assertTrue(file_exists($filename)); + $file = new \Slim\Psr7\UploadedFile($this->fileToStreamInterface($filename), $name); + + $app = $this->tester->createApp($credentials, 'POST', '/folders/{id}/file-refs', FileRefsCreate::class); + + $factory = new ServerRequestFactory(); + $serverParams = [ + 'PHP_AUTH_USER' => $credentials['username'], + 'PHP_AUTH_PW' => $credentials['password'], + ]; + $request = $factory->createServerRequest('POST', '/folders/' . $folder->id . '/file-refs', $serverParams); + $request = $request->withUploadedFiles([$file])->withHeader('Content-Type', 'multipart/form-data'); + + $response = $this->tester->sendMockRequest($app, $request); + $this->tester->assertSame(201, $response->getStatusCode()); + $this->tester->assertArrayHasKey('Location', $response->getHeaders()); + } + // **** helper functions **** private function sendCreateFileRefInFolder($user, $folder, $name, $description, $license) { - $app = $this->tester->createApp( - $user, - 'POST', - '/folders/{id}/file-refs', - FileRefsCreate::class - ); + $app = $this->tester->createApp($user, 'POST', '/folders/{id}/file-refs', FileRefsCreate::class); $requestBuilder = $this->tester->createRequestBuilder($user); $requestBuilder ->setJsonApiBody($this->prepareValidFileRefBody($name, $description, $license)) - ->setUri('/folders/'.($folder->id).'/file-refs') + ->setUri('/folders/' . $folder->id . '/file-refs') ->create(); return $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); @@ -195,24 +186,12 @@ class FileRefsCreateTest extends \Codeception\Test\Unit private function sendCopyFileInFolder($credentials, $folder, $file, $name, $description, $license) { - $app = $this->tester->createApp( - $credentials, - 'POST', - '/folders/{id}/file-refs', - FileRefsCreate::class - ); + $app = $this->tester->createApp($credentials, 'POST', '/folders/{id}/file-refs', FileRefsCreate::class); $requestBuilder = $this->tester->createRequestBuilder($credentials); $requestBuilder - ->setJsonApiBody( - $this->prepareValidFileRefBody( - $name, - $description, - $license, - $file - ) - ) - ->setUri('/folders/'.($folder->id).'/file-refs') + ->setJsonApiBody($this->prepareValidFileRefBody($name, $description, $license, $file)) + ->setUri('/folders/' . $folder->id . '/file-refs') ->create(); return $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); @@ -235,4 +214,11 @@ class FileRefsCreateTest extends \Codeception\Test\Unit $resourceLink = $resource->relationship('terms-of-use')->firstResourceLink(); $this->tester->assertSame($license->id, $resourceLink['id']); } + + private function fileToStreamInterface(string $filename) + { + $factory = new \Slim\Psr7\Factory\StreamFactory(); + + return $factory->createStreamFromFile($filename); + } } diff --git a/tests/jsonapi/FileRefsDeleteTest.php b/tests/jsonapi/FileRefsDeleteTest.php index d1813a4380c2aaea89305d489f7f64a4111605a9..8b30e0d184c7b02abc884149364030d4b79758b2 100644 --- a/tests/jsonapi/FileRefsDeleteTest.php +++ b/tests/jsonapi/FileRefsDeleteTest.php @@ -41,9 +41,8 @@ class FileRefsDeleteTest extends \Codeception\Test\Unit $credentials = $this->tester->getCredentialsForTestDozent(); $missingId = 'missing-id'; - $this->tester->expectThrowable(RecordNotFoundException::class, function () use ($credentials, $missingId) { - $this->sendDeleteFileRef($credentials, $missingId); - }); + $response = $this->sendDeleteFileRef($credentials, $missingId); + $this->tester->assertSame(404, $response->getStatusCode()); } // **** helper functions **** diff --git a/tests/jsonapi/FileRefsShowTest.php b/tests/jsonapi/FileRefsShowTest.php index 10dc0356758f854d59e8fc8b0980c2e62c1c3aa9..6fcca0ac800b49a1caaad8967e43cbb119352bc4 100644 --- a/tests/jsonapi/FileRefsShowTest.php +++ b/tests/jsonapi/FileRefsShowTest.php @@ -45,9 +45,8 @@ class FileRefsShowTest extends \Codeception\Test\Unit { $credentials = $this->tester->getCredentialsForTestDozent(); - $this->tester->expectThrowable(RecordNotFoundException::class, function () use ($credentials) { - $this->sendShowFileRef($credentials, 'missing-id'); - }); + $response = $this->sendShowFileRef($credentials, 'missing-id'); + $this->tester->assertSame(404, $response->getStatusCode()); } // **** helper functions **** diff --git a/tests/jsonapi/ForumCategoriesCreateTest.php b/tests/jsonapi/ForumCategoriesCreateTest.php index c9a12fb5b592522ae3212c5e0dc8820e3f68bb77..4fd96d435a01d1e1a8b58b12f8d847ca3249b63f 100644 --- a/tests/jsonapi/ForumCategoriesCreateTest.php +++ b/tests/jsonapi/ForumCategoriesCreateTest.php @@ -48,25 +48,20 @@ class ForumCategoriesCreateTest extends \Codeception\Test\Unit public function testShouldNotCreateCategory() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForTestAutor(); - $cat = $this->createCategory($credentials); - $course_id = 'badCourse'; - $cat_document = $this->buildValidResourceCategory(); - $app = $this->tester->createApp($credentials, 'POST', '/courses/{id}/forum-categories', ForumCategoriesCreate::class); + $credentials = $this->tester->getCredentialsForTestAutor(); + $cat = $this->createCategory($credentials); + $course_id = 'badCourse'; + $cat_document = $this->buildValidResourceCategory(); + $app = $this->tester->createApp($credentials, 'POST', '/courses/{id}/forum-categories', ForumCategoriesCreate::class); - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/courses/'.$course_id.'/forum-categories') - ->create() - ->setJsonApiBody($cat_document); + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/courses/'.$course_id.'/forum-categories') + ->create() + ->setJsonApiBody($cat_document); - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - $this->tester->assertTrue($response->isSuccessfulDocument([201])); - $document = $response->document(); - $resourceObject = $document->primaryResource(); - $this->tester->assertSame($cat->entry_name, $resourceObject->attribute('title')); - }); + $this->tester->assertSame(404, $response->getStatusCode()); } } diff --git a/tests/jsonapi/ForumCategoriesIndexTest.php b/tests/jsonapi/ForumCategoriesIndexTest.php index 5ef4096bcded1b533812705507ed42cad7c05fca..01ba294d355806f4465198e737201fa497610966 100644 --- a/tests/jsonapi/ForumCategoriesIndexTest.php +++ b/tests/jsonapi/ForumCategoriesIndexTest.php @@ -39,29 +39,22 @@ class ForumCategoriesIndexTest extends \Codeception\Test\Unit $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); $this->tester->assertTrue($response->isSuccessfulDocument([200])); - $document = $response->document(); - $resourceObject = $document->primaryResource(); } public function testShouldNotShowCategory() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForTestDozent(); - $course_id = 'a07535cf2f8a72df33c12ddfa4b53dde'; - $cat = $this->createCategory($credentials); - - $app = $this->tester->createApp($credentials, 'get', '/course/{id}/forum-categories', ForumCategoriesIndex::class); + $credentials = $this->tester->getCredentialsForTestDozent(); + $course_id = 'a07535cf2f8a72df33c12ddfa4b53dde'; + $cat = $this->createCategory($credentials); - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/course/badID/forum-categories') - ->fetch(); + $app = $this->tester->createApp($credentials, 'get', '/course/{id}/forum-categories', ForumCategoriesIndex::class); - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/course/badID/forum-categories') + ->fetch(); - $this->tester->assertTrue($response->isSuccessfulDocument([200])); - $document = $response->document(); - $resourceObject = $document->primaryResource(); - }); + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertSame(404, $response->getStatusCode()); } } diff --git a/tests/jsonapi/ForumCategoriesShowTest.php b/tests/jsonapi/ForumCategoriesShowTest.php index 710a7b1a1bb0e5c97109c7e907e574174571eaab..4e8df261b8a4328875214736dd34514219f8ff38 100644 --- a/tests/jsonapi/ForumCategoriesShowTest.php +++ b/tests/jsonapi/ForumCategoriesShowTest.php @@ -47,24 +47,16 @@ class ForumCategoriesShowTest extends \Codeception\Test\Unit public function testShouldNotShowCategories() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForTestDozent(); + $credentials = $this->tester->getCredentialsForTestDozent(); - $app = $this->tester->createApp($credentials, 'get', '/forum-categories/{id}', ForumCategoriesShow::class); - - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/forum-categories/'.'badId') - ->fetch(); - - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $app = $this->tester->createApp($credentials, 'get', '/forum-categories/{id}', ForumCategoriesShow::class); - $this->tester->assertTrue($response->isSuccessfulDocument([200])); - $document = $response->document(); - $resourceObject = $document->primaryResource(); + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/forum-categories/'.'badId') + ->fetch(); - $this->tester->assertSame($cat->entry_name, $resourceObject->attribute('title')); - $this->tester->assertSame((int) $cat->pos, $resourceObject->attribute('position')); - }); + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertSame(404, $response->getStatusCode()); } } diff --git a/tests/jsonapi/ForumCategoriesUpdateTest.php b/tests/jsonapi/ForumCategoriesUpdateTest.php index cbcc766f88553be9c4f2625d5532d900bcf1f3fb..f2015cbcbe7c8d68bc388d663f3d82ce2215f3db 100644 --- a/tests/jsonapi/ForumCategoriesUpdateTest.php +++ b/tests/jsonapi/ForumCategoriesUpdateTest.php @@ -47,24 +47,18 @@ class ForumCategoriesUpdateTest extends \Codeception\Test\Unit public function testShouldNotUpdateCategory() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForTestAutor(); - $cat = $this->createCategory($credentials); - $cat_document = $this->buildValidResourceCategoryUpdate(); - $app = $this->tester->createApp($credentials, 'PATCH', '/forum-categories/{id}', ForumCategoriesUpdate::class); - - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/forum-categories/badId') - ->update() - ->setJsonApiBody($cat_document); + $credentials = $this->tester->getCredentialsForTestAutor(); + $cat = $this->createCategory($credentials); + $cat_document = $this->buildValidResourceCategoryUpdate(); + $app = $this->tester->createApp($credentials, 'PATCH', '/forum-categories/{id}', ForumCategoriesUpdate::class); - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/forum-categories/badId') + ->update() + ->setJsonApiBody($cat_document); - $this->tester->assertTrue($response->isSuccessfulDocument([200])); - $document = $response->document(); - $resourceObject = $document->primaryResource(); - $this->tester->assertNotEquals($cat->entry_name, $resourceObject->attribute('title')); - }); + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertSame(404, $response->getStatusCode()); } } diff --git a/tests/jsonapi/ForumCategoryDeleteTest.php b/tests/jsonapi/ForumCategoryDeleteTest.php index 2805f53cf01755f198fd595090ec48e867fe756e..8d144f2b1f57e6895b04dc7dc3ab9f28afcbc233 100644 --- a/tests/jsonapi/ForumCategoryDeleteTest.php +++ b/tests/jsonapi/ForumCategoryDeleteTest.php @@ -44,19 +44,17 @@ class ForumCategoryDeleteTest extends \Codeception\Test\Unit public function testShouldNotDeleteEntry() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForTestDozent(); - $cat = $this->createCategory($credentials); - $entry = $this->createEntry($credentials, $cat->id); - $app = $this->tester->createApp($credentials, 'delete', '/forum-categories/{id}', ForumCategoriesDelete::class); - - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/forum-categories/badId') - ->delete(); - - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - $this->tester->assertIsEmpty(ForumCat::find($cat->id)); - }); + $credentials = $this->tester->getCredentialsForTestDozent(); + $cat = $this->createCategory($credentials); + $entry = $this->createEntry($credentials, $cat->id); + $app = $this->tester->createApp($credentials, 'delete', '/forum-categories/{id}', ForumCategoriesDelete::class); + + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/forum-categories/badId') + ->delete(); + + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertSame(404, $response->getStatusCode()); } } diff --git a/tests/jsonapi/ForumEntriesCreateTest.php b/tests/jsonapi/ForumEntriesCreateTest.php index 6f374a3c843eaa2b8724c71174ad9b100a1809ae..04d119e6b7bef83d23de75930edf827e5efb8fa1 100644 --- a/tests/jsonapi/ForumEntriesCreateTest.php +++ b/tests/jsonapi/ForumEntriesCreateTest.php @@ -52,27 +52,21 @@ class ForumEntriesCreateTest extends \Codeception\Test\Unit public function testShouldNotCreateEntryForCategory() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForTestDozent(); - $cat = $this->createCategory($credentials); - $content = 'some content to test'; - $title = 'entry-test-title'; - $entry_json = $this->buildValidResourceEntry($content, $title); - $app = $this->tester->createApp($credentials, 'post', '/forum-categories/{id}/entries', ForumCategoryEntriesCreate::class); - - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/forum-categories/'.'badId'.'/entries') - ->create() - ->setJsonApiBody($entry_json); - - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - $this->tester->assertTrue($response->isSuccessfulDocument([201])); - $document = $response->document(); - $resourceObject = $document->primaryResource(); - $this->tester->assertNotNull($resourceObject->attribute('title')); - $this->tester->assertNotNull($resourceObject->attribute('content')); - }); + $credentials = $this->tester->getCredentialsForTestDozent(); + $cat = $this->createCategory($credentials); + $content = 'some content to test'; + $title = 'entry-test-title'; + $entry_json = $this->buildValidResourceEntry($content, $title); + $app = $this->tester->createApp($credentials, 'post', '/forum-categories/{id}/entries', ForumCategoryEntriesCreate::class); + + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/forum-categories/'.'badId'.'/entries') + ->create() + ->setJsonApiBody($entry_json); + + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertSame(404, $response->getStatusCode()); } public function testShouldCreateEntryForEntry() @@ -101,28 +95,21 @@ class ForumEntriesCreateTest extends \Codeception\Test\Unit public function testShouldNotCreateEntryForEntry() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForTestDozent(); - $cat = $this->createCategory($credentials); - $entry = $this->createEntry($credentials, $cat->id); - $content = 'some new content to test'; - $title = 'entry-test-title new'; - $entry_json = $this->buildValidResourceEntry($content, $title); - $app = $this->tester->createApp($credentials, 'post', '/forum-entries/{id}/entries', ForumEntryEntriesCreate::class); - - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/forum-entries/'.'badID'.'/entries') - ->create() - ->setJsonApiBody($entry_json); - - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - - $this->tester->assertTrue($response->isSuccessfulDocument([201])); - $document = $response->document(); - $resourceObject = $document->primaryResource(); - $this->tester->assertNotNull($resourceObject->attribute('title')); - $this->tester->assertNotNull($resourceObject->attribute('content')); - }); + $credentials = $this->tester->getCredentialsForTestDozent(); + $cat = $this->createCategory($credentials); + $entry = $this->createEntry($credentials, $cat->id); + $content = 'some new content to test'; + $title = 'entry-test-title new'; + $entry_json = $this->buildValidResourceEntry($content, $title); + $app = $this->tester->createApp($credentials, 'post', '/forum-entries/{id}/entries', ForumEntryEntriesCreate::class); + + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/forum-entries/'.'badID'.'/entries') + ->create() + ->setJsonApiBody($entry_json); + + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertSame(404, $response->getStatusCode()); } } diff --git a/tests/jsonapi/ForumEntriesDeleteTest.php b/tests/jsonapi/ForumEntriesDeleteTest.php index 5af0b89b7475e7b7964c19619f91cdd903fb3ece..60ae3a6492c36c91fd6a9781bcf781697ebb9bc1 100644 --- a/tests/jsonapi/ForumEntriesDeleteTest.php +++ b/tests/jsonapi/ForumEntriesDeleteTest.php @@ -46,20 +46,18 @@ class ForumEntriesDeleteTest extends \Codeception\Test\Unit public function testShouldNotDeleteEntry() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForTestDozent(); - $cat = $this->createCategory($credentials); - $entry = $this->createEntry($credentials, $cat->id); - $app = $this->tester->createApp($credentials, 'delete', '/forum-entries/{id}', ForumEntriesDelete::class); + $credentials = $this->tester->getCredentialsForTestDozent(); + $cat = $this->createCategory($credentials); + $entry = $this->createEntry($credentials, $cat->id); + $app = $this->tester->createApp($credentials, 'delete', '/forum-entries/{id}', ForumEntriesDelete::class); - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/forum-entries/badId') - ->delete() - ->setJsonApiBody($entry_json); + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/forum-entries/badId') + ->delete() + ->setJsonApiBody($entry_json); - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - $this->tester->assertIsEmpty(ForumEntry::find($entry->id)); - }); + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertSame(404, $response->getStatusCode()); } } diff --git a/tests/jsonapi/ForumEntriesShowTest.php b/tests/jsonapi/ForumEntriesShowTest.php index 45f9e6a8537f5444ce0d36bb444bcf302aaf1857..2443fa64de9b5f6d541444f5510451cf0e02ef1f 100644 --- a/tests/jsonapi/ForumEntriesShowTest.php +++ b/tests/jsonapi/ForumEntriesShowTest.php @@ -61,42 +61,35 @@ class ForumEntriesShowTest extends \Codeception\Test\Unit public function testShouldNotShowEntry() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForRoot(); - $app = $this->tester->createApp($credentials, 'get', '/forum-entries/{id}', ForumEntriesShow::class); - - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/forum-entries/'.'badEntry') - ->fetch(); + $credentials = $this->tester->getCredentialsForRoot(); + $app = $this->tester->createApp($credentials, 'get', '/forum-entries/{id}', ForumEntriesShow::class); - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/forum-entries/'.'badEntry') + ->fetch(); - $this->tester->assertTrue($response->isSuccessfulDocument([200])); - }); + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertSame(404, $response->getStatusCode()); } public function testShouldNotShowEntriesForCategory() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForRoot(); - $cat = $this->createCategory($credentials); - $this->createEntry($credentials, $cat->id); - $this->createEntry($credentials, $cat->id); - $this->createEntry($credentials, $cat->id); - - $app = $this->tester->createApp($credentials, 'get', '/forum-categories/{id}/entries', ForumCategoryEntriesIndex::class); - - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/forum-categories/badID/entries') - ->fetch(); - - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - $document = $response->document(); - $resourceObject = $document->primaryResource(); - $this->tester->assertNotNull($resourceObject); - }); + $credentials = $this->tester->getCredentialsForRoot(); + $cat = $this->createCategory($credentials); + $this->createEntry($credentials, $cat->id); + $this->createEntry($credentials, $cat->id); + $this->createEntry($credentials, $cat->id); + + $app = $this->tester->createApp($credentials, 'get', '/forum-categories/{id}/entries', ForumCategoryEntriesIndex::class); + + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/forum-categories/badID/entries') + ->fetch(); + + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertSame(404, $response->getStatusCode()); } public function testShouldShowEntriesForCategory() @@ -116,7 +109,7 @@ class ForumEntriesShowTest extends \Codeception\Test\Unit $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); $document = $response->document(); - $resourceObject = $document->primaryResource(); + $resourceObject = $document->primaryResources(); $this->tester->assertNotNull($resourceObject); } @@ -137,30 +130,26 @@ class ForumEntriesShowTest extends \Codeception\Test\Unit $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); $document = $response->document(); - $resourceObject = $document->primaryResource(); + $resourceObject = $document->primaryResources(); $this->tester->assertNotNull($resourceObject); } public function testShouldNotShowEntriesForEntry() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForRoot(); - $cat = $this->createCategory($credentials); - $targetEntry = $this->createEntry($credentials, $cat->id); - $this->createEntry($credentials, $targetEntry->id); - $this->createEntry($credentials, $targetEntry->id); - $this->createEntry($credentials, $targetEntry->id); - $app = $this->tester->createApp($credentials, 'get', '/forum-entries/{id}/entries', ForumEntryEntriesIndex::class); - - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/forum-entries/badTopic/entries') - ->fetch(); - - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - $document = $response->document(); - $resourceObject = $document->primaryResource(); - $this->tester->assertNotNull($resourceObject); - }); + $credentials = $this->tester->getCredentialsForRoot(); + $cat = $this->createCategory($credentials); + $targetEntry = $this->createEntry($credentials, $cat->id); + $this->createEntry($credentials, $targetEntry->id); + $this->createEntry($credentials, $targetEntry->id); + $this->createEntry($credentials, $targetEntry->id); + $app = $this->tester->createApp($credentials, 'get', '/forum-entries/{id}/entries', ForumEntryEntriesIndex::class); + + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/forum-entries/badTopic/entries') + ->fetch(); + + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertSame(404, $response->getStatusCode()); } } diff --git a/tests/jsonapi/ForumEntriesUpdateTest.php b/tests/jsonapi/ForumEntriesUpdateTest.php index 91f2c54c7553565ae085615fffac5241e427ae43..db08917defded0f9cd2fb06827024f3a51b1439f 100644 --- a/tests/jsonapi/ForumEntriesUpdateTest.php +++ b/tests/jsonapi/ForumEntriesUpdateTest.php @@ -48,24 +48,19 @@ class ForumEntriesUpdateTest extends \Codeception\Test\Unit public function testShouldNotUpdateEntry() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForTestDozent(); - $cat = $this->createCategory($credentials); - $entry = $this->createEntry($credentials, $cat->id); - $entry_json = $this->buildValidResourceEntryUpdate(); - $app = $this->tester->createApp($credentials, 'PATCH', '/forum-entries/{id}', ForumEntriesUpdate::class); + $credentials = $this->tester->getCredentialsForTestDozent(); + $cat = $this->createCategory($credentials); + $entry = $this->createEntry($credentials, $cat->id); + $entry_json = $this->buildValidResourceEntryUpdate(); + $app = $this->tester->createApp($credentials, 'PATCH', '/forum-entries/{id}', ForumEntriesUpdate::class); - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/forum-entries/badId') - ->update() - ->setJsonApiBody($entry_json); + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/forum-entries/badId') + ->update() + ->setJsonApiBody($entry_json); - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - $this->tester->assertTrue($response->isSuccessfulDocument([200])); - $document = $response->document(); - $resourceObject = $document->primaryResource(); - $this->tester->assertNotEquals($entry->name, $resourceObject->attribute('title')); - }); + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertSame(404, $response->getStatusCode()); } } diff --git a/tests/jsonapi/MessagesShowTest.php b/tests/jsonapi/MessagesShowTest.php index 9bf5464598971f33cd50f897657fa60d50516bf4..b9563dc7bf0ad998893a9ea949c3e699fc9dc5b1 100644 --- a/tests/jsonapi/MessagesShowTest.php +++ b/tests/jsonapi/MessagesShowTest.php @@ -23,10 +23,9 @@ class MessagesShowTest extends \Codeception\Test\Unit // tests public function testMessageNotFound() { - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $credentials = $this->tester->getCredentialsForTestAutor(); - $response = $this->fetchMessage($credentials, new \Message(md5('eurydamas'))); - }); + $credentials = $this->tester->getCredentialsForTestAutor(); + $response = $this->fetchMessage($credentials, new \Message(md5('eurydamas'))); + $this->tester->assertSame(404, $response->getStatusCode()); } public function testShowMessage() diff --git a/tests/jsonapi/NewsCreateTest.php b/tests/jsonapi/NewsCreateTest.php index 199cea597bb56bf138529c1b07c29836335f26fc..eaf9dfd7e1f1c22fed2f8b30e1ecc4fa63437e78 100644 --- a/tests/jsonapi/NewsCreateTest.php +++ b/tests/jsonapi/NewsCreateTest.php @@ -1,16 +1,12 @@ <?php require_once 'NewsTestHelper.php'; -use JsonApi\Models\C; +use JsonApi\Routes\News\CommentCreate; use JsonApi\Routes\News\CourseNewsCreate; -use JsonApi\Routes\News\UserNewsCreate; +use JsonApi\Routes\News\NewsUpdate; use JsonApi\Routes\News\StudipNewsCreate; -use JsonApi\Routes\News\CommentCreate; -use JsonApi\Routes\News\NewsUpdate; -use JsonApi\Errors\AuthorizationFailedException; -use JsonApi\Errors\RecordNotFoundException; -use JsonApi\Routes\News\CommentsDelete; +use JsonApi\Routes\News\UserNewsCreate; class NewsCreateTest extends \Codeception\Test\Unit { @@ -53,49 +49,43 @@ class NewsCreateTest extends \Codeception\Test\Unit $this->tester->assertNotNull($resourceObject->attribute('content')); $newsId = $news->id; } + public function testShouldNotStudipNewsCreate() { + $credentials = $this->tester->getCredentialsForTestDozent(); + $title = 'A public testing title'; + $content = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit'; + $entry_json = $this->buildValidResourceEntry($content, $title); + $app = $this->tester->createApp($credentials, 'post', '/news', StudipNewsCreate::class); + + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/news') + ->create() + ->setJsonApiBody($entry_json); - $this->tester->expectThrowable(AuthorizationFailedException::class, function () { - $credentials = $this->tester->getCredentialsForTestDozent(); - $title = 'A public testing title'; - $content = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit'; - $entry_json = $this->buildValidResourceEntry($content, $title); - $app = $this->tester->createApp($credentials, 'post', '/news', StudipNewsCreate::class); - - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/news') - ->create() - ->setJsonApiBody($entry_json); - - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - $this->tester->assertTrue($response->isSuccessfulDocument([201])); - $document = $response->document(); - $resourceObject = $document->primaryResource(); - $this->tester->assertNotNull($resourceObject->attribute('title')); - $this->tester->assertNotNull($resourceObject->attribute('content')); - $newsId = $news->id; - - }); + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertFalse($response->isSuccessfulDocument()); + $this->tester->assertSame(403, $response->getStatusCode()); } - public function testShouldNewsUpdate() { + + public function testShouldNewsUpdate() + { $title = 'A course testing title'; $credentials = $this->tester->getCredentialsForTestDozent(); $content = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit'; $news = $this->createNews($credentials, $title, $content); - + $changedContent = 'Lorem ipsum dolor sit amet'; $entry_json = $this->buildValidUpdateEntry($changedContent); $app = $this->tester->createApp($credentials, 'patch', '/news/{id}', NewsUpdate::class); - + $requestBuilder = $this->tester->createRequestBuilder($credentials); $requestBuilder ->setUri('/news/'.$news->id) ->update() ->setJsonApiBody($entry_json); - - + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); $this->tester->assertTrue($response->isSuccessfulDocument()); @@ -128,10 +118,9 @@ class NewsCreateTest extends \Codeception\Test\Unit $this->tester->assertNotNull($resourceObject->attribute('content')); $newsId = $news->id; } + public function testShouldNotCourseNewsCreate() { - $this->tester->expectThrowable(AuthorizationFailedException::class, function () { - $credentials = $this->tester->getCredentialsForTestAutor(); $courseId = 'a07535cf2f8a72df33c12ddfa4b53dde'; $title = 'A course testing title'; @@ -147,15 +136,9 @@ class NewsCreateTest extends \Codeception\Test\Unit $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - $this->tester->assertTrue($response->isSuccessfulDocument([201])); - $document = $response->document(); - $resourceObject = $document->primaryResource(); - $this->tester->assertNotNull($resourceObject->attribute('title')); - $this->tester->assertNotNull($resourceObject->attribute('content')); - $newsId = $news->id; - - }); + $this->tester->assertSame(403, $response->getStatusCode()); } + public function testShouldUserNewsCreate() { $credentials = $this->tester->getCredentialsForTestAutor(); @@ -172,7 +155,6 @@ class NewsCreateTest extends \Codeception\Test\Unit ->setJsonApiBody($entry_json); $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - $this->tester->assertTrue($response->isSuccessfulDocument([201])); $document = $response->document(); $resourceObject = $document->primaryResource(); @@ -180,10 +162,9 @@ class NewsCreateTest extends \Codeception\Test\Unit $this->tester->assertNotNull($resourceObject->attribute('content')); $newsId = $news->id; } + public function testShouldNotUserNewsCreate() { - $this->tester->expectThrowable(AuthorizationFailedException::class, function () { - $credentials = $this->tester->getCredentialsForTestAutor(); $otherUser = $this->tester->getCredentialsForTestDozent(); $userId = $otherUser['id']; @@ -199,16 +180,9 @@ class NewsCreateTest extends \Codeception\Test\Unit ->setJsonApiBody($entry_json); $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - - $this->tester->assertTrue($response->isSuccessfulDocument([201])); - $document = $response->document(); - $resourceObject = $document->primaryResource(); - $this->tester->assertNotNull($resourceObject->attribute('title')); - $this->tester->assertNotNull($resourceObject->attribute('content')); - $newsId = $news->id; - - }); + $this->assertSame(403, $response->getStatusCode()); } + public function testShouldCommentCreate() { $title = 'A course testing title'; @@ -227,37 +201,29 @@ class NewsCreateTest extends \Codeception\Test\Unit $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - $this->tester->assertTrue($response->isSuccessfulDocument([201])); + $this->tester->assertTrue($response->isSuccessfulDocument()); $document = $response->document(); $resourceObject = $document->primaryResource(); $this->tester->assertNotNull($resourceObject->attribute('content')); } + public function testShouldNotCommentCreate() { - //missing title - $this->tester->expectThrowable(RecordNotFoundException::class, function () { - $title = 'A course testing title'; - $credentials = $this->tester->getCredentialsForTestDozent(); - $content = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit'; - $news = $this->createNews($credentials, $title, $content); - $comment = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit'; - $entry_json = $this->buildValidCommentEntry($comment); - - $app = $this->tester->createApp($credentials, 'post', '/news/{id}/comments', CommentCreate::class); - $requestBuilder = $this->tester->createRequestBuilder($credentials); - $requestBuilder - ->setUri('/news/badId/comments') - ->create() - ->setJsonApiBody($entry_json); - - $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); - - $this->tester->assertTrue($response->isSuccessfulDocument([201])); - $document = $response->document(); - $resourceObject = $document->primaryResource(); - $this->tester->assertNotNull($resourceObject->attribute('content')); - }); - } - + $title = 'A course testing title'; + $credentials = $this->tester->getCredentialsForTestDozent(); + $content = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit'; + $news = $this->createNews($credentials, $title, $content); + $comment = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit'; + $entry_json = $this->buildValidCommentEntry($comment); + $app = $this->tester->createApp($credentials, 'post', '/news/{id}/comments', CommentCreate::class); + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder + ->setUri('/news/badId/comments') + ->create() + ->setJsonApiBody($entry_json); + + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + $this->tester->assertFalse($response->isSuccessfulDocument()); + } } diff --git a/tests/jsonapi/NewsShowTest.php b/tests/jsonapi/NewsShowTest.php index 79df86db928b3db20bb161ca1cc558c7e13e44e1..6a90657f6304497dfc9a24bc42b0e69165cb3c95 100644 --- a/tests/jsonapi/NewsShowTest.php +++ b/tests/jsonapi/NewsShowTest.php @@ -35,7 +35,7 @@ class NewsShowTest extends \Codeception\Test\Unit $news = $this->createNews($credentials, $title, $content, $range_id); $newsId = $news->id; $app = $this->tester->createApp($credentials, 'get', '/studip/news', GlobalNewsShow::class); - + $response = $this->tester->sendMockRequest( $app, $this->tester->createRequestBuilder($credentials) @@ -47,11 +47,12 @@ class NewsShowTest extends \Codeception\Test\Unit $this->tester->assertSame(200, $response->getStatusCode()); $this->tester->assertTrue($response->isSuccessfulDocument([200])); $document = $response->document(); - $resourceObject = $document->primaryResource(); + $resourceObjects = $document->primaryResources(); + $resourceObject = current($resourceObjects); $this->tester->assertNotNull($resourceObject->attribute('title')); $this->tester->assertNotNull($resourceObject->attribute('content')); $this->tester->assertNotNull($document->isSingleResourceDocument()); - $this->tester->assertSame($newsId, $document->primaryResource()->id()); + $this->tester->assertSame($newsId, $resourceObject->id()); $this->tester->storeJsonMd('show_news', $response); } @@ -64,7 +65,7 @@ class NewsShowTest extends \Codeception\Test\Unit $news = $this->createNews($credentials, $title, $content, $course_id); $newsId = $news->id; $app = $this->tester->createApp($credentials, 'get', '/courses/{id}/news', ByCourseIndex::class); - + $response = $this->tester->sendMockRequest( $app, $this->tester->createRequestBuilder($credentials) @@ -74,10 +75,11 @@ class NewsShowTest extends \Codeception\Test\Unit ); $this->tester->assertTrue($response->isSuccessfulDocument()); $document = $response->document(); - $resourceObject = $document->primaryResource(); + $resourceObjects = $document->primaryResources(); + $resourceObject = current($resourceObjects); $this->tester->assertNotNull($resourceObject->attribute('title')); $this->tester->assertNotNull($resourceObject->attribute('content')); - + } public function testShouldShowNewsByCurrentUser() @@ -92,8 +94,7 @@ class NewsShowTest extends \Codeception\Test\Unit $this->tester->assertSame(200, $response->getStatusCode()); $this->tester->assertTrue($response->isSuccessfulDocument([200])); $document = $response->document(); - $this->tester->assertNotNull($document->primaryResource()); - $this->tester->assertSame($newsId, $document->primaryResource()->id()); + $this->tester->assertNotEmpty($document->primaryResources()); } public function testShouldNotShowNewsByCurrentUser() @@ -107,7 +108,7 @@ class NewsShowTest extends \Codeception\Test\Unit $this->tester->assertSame(200, $response->getStatusCode()); $this->tester->assertTrue($response->isSuccessfulDocument([200])); $document = $response->document(); - $this->tester->assertNull($document->primaryResource()); + $this->tester->assertEmpty($document->primaryResources()); } private function getNoNewsByUser($credentials) diff --git a/tests/jsonapi/UserEventsIcalTest.php b/tests/jsonapi/UserEventsIcalTest.php index bf3d2ba5104b91d12a14cba3d607a8b2343b5a44..3d0a78a31c17405f938e4608b285ac4b055b286f 100644 --- a/tests/jsonapi/UserEventsIcalTest.php +++ b/tests/jsonapi/UserEventsIcalTest.php @@ -39,7 +39,7 @@ class UserEventsIcalTest extends \Codeception\Test\Unit $requestBuilder = $this->tester->createRequestBuilder($credentials); $requestBuilder->setUri('/users/'.$credentials['id'].'/events.ics')->fetch(); - $response = $app($requestBuilder->getRequest(), new \Slim\Http\Response()); + $response = $app->handle($requestBuilder->getRequest()); $this->tester->assertEquals(200, $response->getStatusCode()); $this->tester->assertStringContainsString('BEGIN:VEVENT', (string) $response->getBody()); diff --git a/tests/jsonapi/UserScheduleShowTest.php b/tests/jsonapi/UserScheduleShowTest.php index f505977b104f68c1b69ebc90867f644dbf8ead87..fc7529f8ebfc26eaeda6fc650c143d19588fb7b1 100644 --- a/tests/jsonapi/UserScheduleShowTest.php +++ b/tests/jsonapi/UserScheduleShowTest.php @@ -38,6 +38,7 @@ class UserScheduleShowTest extends \Codeception\Test\Unit $scheduleId = \DBManager::get()->lastInsertId(); $app = $this->tester->createApp($credentials, 'get', '/users/{id}/schedule', UserScheduleShow::class, 'get-schedule'); + $app->get('/xxx', function () {})->setName('get-semester'); $requestBuilder = $this->tester->createRequestBuilder($credentials); $requestBuilder->setUri('/users/'.$credentials['id'].'/schedule')->fetch(); diff --git a/tests/jsonapi/_bootstrap.php b/tests/jsonapi/_bootstrap.php index b4481afb7f6660e58af38e9ed013f0e63612ff72..d9c5adcef74f6097bcfd246aef501bd59a62da93 100644 --- a/tests/jsonapi/_bootstrap.php +++ b/tests/jsonapi/_bootstrap.php @@ -55,6 +55,7 @@ StudipAutoloader::addAutoloadPath($GLOBALS['STUDIP_BASE_PATH'].'/lib/calendar/li StudipAutoloader::addAutoloadPath($GLOBALS['STUDIP_BASE_PATH'].'/lib/filesystem'); StudipAutoloader::addAutoloadPath($GLOBALS['STUDIP_BASE_PATH'].'/lib/migrations'); StudipAutoloader::addAutoloadPath($GLOBALS['STUDIP_BASE_PATH'].'/lib/modules'); +StudipAutoloader::addAutoloadPath($GLOBALS['STUDIP_BASE_PATH'].'/lib/navigation'); StudipAutoloader::addAutoloadPath($GLOBALS['STUDIP_BASE_PATH'].'/lib/phplib'); StudipAutoloader::addAutoloadPath($GLOBALS['STUDIP_BASE_PATH'].'/lib/raumzeit'); StudipAutoloader::addAutoloadPath($GLOBALS['STUDIP_BASE_PATH'].'/lib/resources');