diff --git a/.github/workflows/blog-api_build.yml b/.github/workflows/blog-api_build.yml index 297590dde..9ad9ca26c 100644 --- a/.github/workflows/blog-api_build.yml +++ b/.github/workflows/blog-api_build.yml @@ -34,7 +34,7 @@ jobs: name: PHP ${{ matrix.php }}-${{ matrix.os }} env: - extensions: fileinfo, pdo, pdo_sqlite, intl + extensions: fileinfo, pdo, pdo_sqlite, intl, pcntl key: cache-v1 YII_C3: true working_directory: blog-api diff --git a/.github/workflows/blog_build.yml b/.github/workflows/blog_build.yml index d1b87bca8..4a010ae65 100644 --- a/.github/workflows/blog_build.yml +++ b/.github/workflows/blog_build.yml @@ -37,7 +37,7 @@ jobs: extensions: fileinfo, pdo, pdo_sqlite, intl key: cache-v1 YII_C3: true - working_directory: blog-api + working_directory: blog runs-on: ${{ matrix.os }} diff --git a/.styleci.yml b/.styleci.yml index 2b00d6317..76e29ece8 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,7 +1,7 @@ preset: psr12 risky: true -version: 8 +version: 8.1 finder: exclude: @@ -60,7 +60,6 @@ enabled: - phpdoc_order - phpdoc_property - phpdoc_scalar - - phpdoc_separation - phpdoc_singular_inheritdoc - phpdoc_trim - phpdoc_trim_consecutive_blank_line_separation @@ -82,3 +81,9 @@ enabled: - trailing_comma_in_multiline_array - unalign_double_arrow - unalign_equals + - empty_loop_body_braces + - integer_literal_case + - union_type_without_spaces + +disabled: + - function_declaration diff --git a/ansible/roles/certbot/tasks/update_certificates.yml b/ansible/roles/certbot/tasks/update_certificates.yml index 02f79c583..7dc919a9f 100644 --- a/ansible/roles/certbot/tasks/update_certificates.yml +++ b/ansible/roles/certbot/tasks/update_certificates.yml @@ -16,3 +16,23 @@ args: chdir: /home/deploy/demo.yiiframework.com shell: docker-compose -f docker-compose.yml exec gateway nginx -t && docker-compose -f docker-compose.yml exec gateway nginx -s reload + +# Crontab file location is /var/spool/cron/crontabs/deploy +# Every 2nd month on 15th day of month +# See https://crontab.guru/#0_0_15_*/2_* +- name: Set periodic certificates update + cron: + name: certbot-renew + user: deploy + minute: '0' + hour: '0' + day: '15' + month: '*/2' + job: > + /bin/bash -c " + cd /home/deploy/demo.yiiframework.com && + docker-compose -f docker-compose.yml up certbot && + sleep 180 && + docker-compose -f docker-compose.yml exec -T gateway nginx -t && + docker-compose -f docker-compose.yml exec -T gateway nginx -s reload + " diff --git a/blog-api/.env.test b/blog-api/.env.test index dbdcc044e..881657317 100644 --- a/blog-api/.env.test +++ b/blog-api/.env.test @@ -1,2 +1,3 @@ YII_ENV=test YII_DEBUG=true +BASE_URL=/ diff --git a/blog-api/composer.json b/blog-api/composer.json index 85557faa3..3eacedb2c 100644 --- a/blog-api/composer.json +++ b/blog-api/composer.json @@ -14,7 +14,7 @@ "issues": "https://github.com/yiisoft/demo-api/issues?state=open", "forum": "https://www.yiiframework.com/forum/", "wiki": "https://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", + "irc": "ircs://irc.libera.chat:6697/yii", "source": "https://github.com/yiisoft/demo-api" }, "minimum-stability": "dev", @@ -27,50 +27,50 @@ "cycle/entity-behavior": "^1.0", "cycle/orm": "^2.0", "doctrine/collections": "^2.0", - "httpsoft/http-message": "^1.0.5", + "httpsoft/http-message": "^1.1", "myclabs/php-enum": "^1.7", "psr/container": "^1.0|^2.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", + "psr/http-message": "^1.1|^2.0", "psr/http-server-handler": "^1.0", "psr/http-server-middleware": "^1.0", "psr/log": "^3.0", "vlucas/phpdotenv": "^5.3", "yiisoft/access": "^1.0", "yiisoft/auth": "^3.0", - "yiisoft/cache": "^2.0", - "yiisoft/cache-file": "^2.0", + "yiisoft/cache": "^3.0", + "yiisoft/cache-file": "^3.0", "yiisoft/config": "^1.0", "yiisoft/data": "^1.0", - "yiisoft/data-response": "^1.0", + "yiisoft/data-response": "^2.0", "yiisoft/definitions": "^3.0", "yiisoft/di": "^1.0", - "yiisoft/error-handler": "^2.0", + "yiisoft/error-handler": "^3.0", "yiisoft/factory": "^1.0", "yiisoft/files": "^2.0", "yiisoft/http": "^1.2", "yiisoft/injector": "^1.0", "yiisoft/log": "^2.0", - "yiisoft/log-target-file": "^2.0", + "yiisoft/log-target-file": "^3.0", "yiisoft/request-body-parser": "^1.1", "yiisoft/request-model": "dev-master", - "yiisoft/router": "^2.1", - "yiisoft/router-fastroute": "^2.1", + "yiisoft/router": "^3.0", + "yiisoft/router-fastroute": "^3.0", "yiisoft/security": "^1.0", - "yiisoft/translator": "^2.0", + "yiisoft/translator": "^3.0", "yiisoft/translator-message-php": "^1.1", - "yiisoft/user": "^1.0", - "yiisoft/validator": "^3.0@dev", - "yiisoft/yii-console": "^1.0", - "yiisoft/yii-cycle": "^3.0@dev", + "yiisoft/user": "^2.0", + "yiisoft/validator": "^1.0", + "yiisoft/yii-console": "^2.0", + "yiisoft/yii-cycle": "dev-master", "yiisoft/yii-debug": "^3.0@dev", - "yiisoft/yii-event": "^1.0", + "yiisoft/yii-event": "^2.0", "yiisoft/yii-http": "^1.0", - "yiisoft/yii-middleware": "dev-master", + "yiisoft/yii-middleware": "^1.0", "yiisoft/yii-queue": "3.0.x-dev", - "yiisoft/yii-runner-console": "^1.0", - "yiisoft/yii-runner-http": "^1.0", - "yiisoft/yii-swagger": "^1.0" + "yiisoft/yii-runner-console": "^2.0", + "yiisoft/yii-runner-http": "^2.0", + "yiisoft/yii-swagger": "^2.0" }, "require-dev": { "codeception/c3": "^2.6", @@ -118,78 +118,7 @@ "branch-alias": { "dev-master": "1.0.x-dev" }, - "config-plugin-options": { - "source-directory": "config" - }, - "config-plugin-environments": { - "dev": { - "params": [ - "test/params.php" - ] - }, - "prod": { - "params": [ - "test/params.php" - ] - }, - "test": { - "params": [ - "test/params.php" - ] - } - }, - "config-plugin": { - "common": "common/*.php", - "params": [ - "params.php", - "?params-local.php" - ], - "web": [ - "$common", - "web/*.php" - ], - "console": [ - "$common", - "console/*.php" - ], - "events": "events.php", - "events-web": [ - "$events", - "events-web.php" - ], - "events-console": [ - "$events", - "events-console.php" - ], - "providers": "providers.php", - "providers-web": [ - "$providers", - "providers-web.php" - ], - "providers-console": [ - "$providers", - "providers-console.php" - ], - "delegates": "delegates.php", - "delegates-web": [ - "$delegates", - "delegates-web.php" - ], - "delegates-console": [ - "$delegates", - "delegates-console.php" - ], - "routes": "routes.php", - "bootstrap": "bootstrap.php", - "bootstrap-web": [ - "$bootstrap", - "bootstrap-web.php" - ], - "bootstrap-console": [ - "$bootstrap", - "bootstrap-console.php" - ] - } + "config-plugin-file": "configuration.php" }, "config": { "sort-packages": true, diff --git a/blog-api/config/.gitignore b/blog-api/config/.gitignore index 704eb157c..8b60a947d 100644 --- a/blog-api/config/.gitignore +++ b/blog-api/config/.gitignore @@ -1,2 +1 @@ .merge-plan.php -*-local.php diff --git a/blog-api/config/bootstrap.php b/blog-api/config/bootstrap.php deleted file mode 100644 index 49544496a..000000000 --- a/blog-api/config/bootstrap.php +++ /dev/null @@ -1,10 +0,0 @@ -get(\Yiisoft\Router\UrlGeneratorInterface::class); - $urlGenerator->setUriPrefix($_ENV['BASE_URL']); - }, -]; diff --git a/blog-api/config/bootstrap-console.php b/blog-api/config/common/bootstrap.php similarity index 100% rename from blog-api/config/bootstrap-console.php rename to blog-api/config/common/bootstrap.php diff --git a/blog-api/config/common/cache.php b/blog-api/config/common/di/cache.php similarity index 100% rename from blog-api/config/common/cache.php rename to blog-api/config/common/di/cache.php diff --git a/blog-api/config/common/cycle.php b/blog-api/config/common/di/cycle.php similarity index 100% rename from blog-api/config/common/cycle.php rename to blog-api/config/common/di/cycle.php diff --git a/blog-api/config/common/logger.php b/blog-api/config/common/di/logger.php similarity index 100% rename from blog-api/config/common/logger.php rename to blog-api/config/common/di/logger.php diff --git a/blog-api/config/common/psr17.php b/blog-api/config/common/di/psr17.php similarity index 100% rename from blog-api/config/common/psr17.php rename to blog-api/config/common/di/psr17.php diff --git a/blog-api/config/common/router.php b/blog-api/config/common/di/router.php similarity index 100% rename from blog-api/config/common/router.php rename to blog-api/config/common/di/router.php diff --git a/blog-api/config/common/translator.php b/blog-api/config/common/di/translator.php similarity index 100% rename from blog-api/config/common/translator.php rename to blog-api/config/common/di/translator.php diff --git a/blog-api/config/common/validator.php b/blog-api/config/common/di/validator.php similarity index 100% rename from blog-api/config/common/validator.php rename to blog-api/config/common/di/validator.php diff --git a/blog-api/config/params.php b/blog-api/config/common/params.php similarity index 82% rename from blog-api/config/params.php rename to blog-api/config/common/params.php index bfd9f32aa..cd550e125 100644 --- a/blog-api/config/params.php +++ b/blog-api/config/common/params.php @@ -7,14 +7,12 @@ use Cycle\Database\Config\SQLiteDriverConfig; use Yiisoft\ErrorHandler\Middleware\ErrorCatcher; use Yiisoft\Router\Middleware\Router; -use Yiisoft\Yii\Cycle\Command\Migration; -use Yiisoft\Yii\Cycle\Command\Schema; use Yiisoft\Yii\Cycle\Schema\Conveyor\AttributedSchemaConveyor; use Yiisoft\Yii\Cycle\Schema\Provider\FromConveyorSchemaProvider; use Yiisoft\Yii\Cycle\Schema\Provider\PhpFileSchemaProvider; use Yiisoft\Yii\Cycle\Schema\SchemaProviderInterface; use Yiisoft\Yii\Middleware\Locale; -use Yiisoft\Yii\Middleware\SubFolder; +use Yiisoft\Yii\Middleware\Subfolder; use Yiisoft\Yii\Queue\Adapter\SynchronousAdapter; return [ @@ -28,17 +26,17 @@ 'supportEmail' => 'support@example.com', 'middlewares' => [ ErrorCatcher::class, - SubFolder::class, + Subfolder::class, Locale::class, Router::class, ], 'yiisoft/aliases' => [ 'aliases' => [ - '@root' => dirname(__DIR__), + '@root' => dirname(__DIR__, 2), '@assets' => '@public/assets', '@assetsUrl' => '@baseUrl/assets', - '@baseUrl' => $_ENV['BASE_URL'], + '@baseUrl' => '', '@data' => '@root/data', '@messages' => '@resources/messages', '@public' => '@root/public', @@ -61,21 +59,6 @@ 'defaultCategory' => 'app', ], - // Console commands - 'yiisoft/yii-console' => [ - 'commands' => [ - 'cycle/schema' => Schema\SchemaCommand::class, - 'cycle/schema/php' => Schema\SchemaPhpCommand::class, - 'cycle/schema/clear' => Schema\SchemaClearCommand::class, - 'cycle/schema/rebuild' => Schema\SchemaRebuildCommand::class, - 'migrate/create' => Migration\CreateCommand::class, - 'migrate/generate' => Migration\GenerateCommand::class, - 'migrate/up' => Migration\UpCommand::class, - 'migrate/down' => Migration\DownCommand::class, - 'migrate/list' => Migration\ListCommand::class, - ], - ], - 'yiisoft/yii-cycle' => [ // DBAL config 'dbal' => [ @@ -90,7 +73,7 @@ ], 'connections' => [ 'sqlite' => new SQLiteDriverConfig( - new FileConnectionConfig(dirname(__DIR__) . '/runtime/database.db') + new FileConnectionConfig(dirname(__DIR__, 2) . '/runtime/database.db') ), ], ], diff --git a/blog-api/config/routes.php b/blog-api/config/common/routes.php similarity index 93% rename from blog-api/config/routes.php rename to blog-api/config/common/routes.php index 6e01dbe76..2d39e0ab8 100644 --- a/blog-api/config/routes.php +++ b/blog-api/config/common/routes.php @@ -15,6 +15,7 @@ use Yiisoft\Router\UrlGeneratorInterface; use Yiisoft\Swagger\Middleware\SwaggerJson; use Yiisoft\Swagger\Middleware\SwaggerUi; +use Yiisoft\Yii\Middleware\CorsAllowAll; return [ Route::get('/') @@ -61,6 +62,7 @@ }), Route::get('/openapi.json') ->middleware(FormatDataResponseAsJson::class) - ->action(SwaggerJson::class), + ->middleware(CorsAllowAll::class) + ->action([SwaggerJson::class, 'handle']), ), ]; diff --git a/blog-api/config/console/.gitkeep b/blog-api/config/console/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/blog-api/config/console/commands.php b/blog-api/config/console/commands.php new file mode 100644 index 000000000..84f641b6e --- /dev/null +++ b/blog-api/config/console/commands.php @@ -0,0 +1,18 @@ + Schema\SchemaCommand::class, + 'cycle/schema/php' => Schema\SchemaPhpCommand::class, + 'cycle/schema/clear' => Schema\SchemaClearCommand::class, + 'cycle/schema/rebuild' => Schema\SchemaRebuildCommand::class, + 'migrate/create' => Migration\CreateCommand::class, + 'migrate/generate' => Migration\GenerateCommand::class, + 'migrate/up' => Migration\UpCommand::class, + 'migrate/down' => Migration\DownCommand::class, + 'migrate/list' => Migration\ListCommand::class, +]; diff --git a/blog-api/config/console/params.php b/blog-api/config/console/params.php new file mode 100644 index 000000000..051a18593 --- /dev/null +++ b/blog-api/config/console/params.php @@ -0,0 +1,9 @@ + [ + 'commands' => require __DIR__ . '/commands.php', + ], +]; diff --git a/blog-api/config/delegates-web.php b/blog-api/config/delegates-web.php deleted file mode 100644 index 0dae23dee..000000000 --- a/blog-api/config/delegates-web.php +++ /dev/null @@ -1,5 +0,0 @@ - [ 'connections' => [ 'sqlite' => new SQLiteDriverConfig( - new FileConnectionConfig(dirname(__DIR__, 2) . '/tests/Support/Data/database.db') + new FileConnectionConfig(dirname(__DIR__, 3) . '/tests/Support/Data/database.db') ), ], ], diff --git a/blog-api/config/events-console.php b/blog-api/config/events-console.php deleted file mode 100644 index 0dae23dee..000000000 --- a/blog-api/config/events-console.php +++ /dev/null @@ -1,5 +0,0 @@ - [ '__construct()' => [ 'dispatcher' => DynamicReference::to(static function (Injector $injector) use ($params) { - return ($injector->make(MiddlewareDispatcher::class)) + return $injector->make(MiddlewareDispatcher::class) ->withMiddlewares($params['middlewares']); }), 'fallbackHandler' => Reference::to(NotFoundHandler::class), @@ -22,8 +22,13 @@ ], \Yiisoft\Yii\Middleware\Locale::class => [ '__construct()' => [ - 'locales' => $params['locale']['locales'], - 'ignoredRequests' => $params['locale']['ignoredRequests'], + 'supportedLocales' => $params['locale']['locales'], + 'ignoredRequestUrlPatterns' => $params['locale']['ignoredRequests'], + ], + ], + \Yiisoft\Yii\Middleware\Subfolder::class => [ + '__construct()' => [ + 'prefix' => !empty(trim($_ENV['BASE_URL'] ?? '', '/')) ? $_ENV['BASE_URL'] : null, ], ], ]; diff --git a/blog-api/config/web/data-response.php b/blog-api/config/web/di/data-response.php similarity index 100% rename from blog-api/config/web/data-response.php rename to blog-api/config/web/di/data-response.php diff --git a/blog-api/config/web/error-handler.php b/blog-api/config/web/di/error-handler.php similarity index 100% rename from blog-api/config/web/error-handler.php rename to blog-api/config/web/di/error-handler.php diff --git a/blog-api/config/web/middleware-dispatcher.php b/blog-api/config/web/di/middleware-dispatcher.php similarity index 100% rename from blog-api/config/web/middleware-dispatcher.php rename to blog-api/config/web/di/middleware-dispatcher.php diff --git a/blog-api/config/web/user.php b/blog-api/config/web/di/user.php similarity index 100% rename from blog-api/config/web/user.php rename to blog-api/config/web/di/user.php diff --git a/blog/config/dev/params.php b/blog-api/config/web/params.php similarity index 100% rename from blog/config/dev/params.php rename to blog-api/config/web/params.php diff --git a/blog-api/configuration.php b/blog-api/configuration.php new file mode 100644 index 000000000..5360ad4fe --- /dev/null +++ b/blog-api/configuration.php @@ -0,0 +1,66 @@ + [ + 'params' => [ + 'common/params.php', + ], + 'params-web' => [ + '$params', + 'web/params.php', + ], + 'params-console' => [ + '$params', + 'console/params.php', + ], + 'di' => 'common/di/*.php', + 'di-web' => [ + '$di', + 'web/di/*.php', + ], + 'di-console' => '$di', + 'di-providers' => [], + 'di-providers-web' => [ + '$di-providers', + ], + 'di-providers-console' => [ + '$di-providers', + ], + 'di-delegates' => [], + 'di-delegates-web' => [ + '$di-delegates', + ], + 'di-delegates-console' => [ + '$di-delegates', + ], + 'events' => [], + 'events-web' => '$events', + 'events-console' => '$events', + 'routes' => 'common/routes.php', + 'bootstrap' => 'common/bootstrap.php', + 'bootstrap-web' => '$bootstrap', + 'bootstrap-console' => '$bootstrap', + ], + 'config-plugin-environments' => [ + 'dev' => [ + 'params' => [ + 'environments/dev/params.php', + ], + ], + 'prod' => [ + 'params' => [ + 'environments/prod/params.php', + ], + ], + 'test' => [ + 'params' => [ + 'environments/test/params.php', + ], + ], + ], + 'config-plugin-options' => [ + 'source-directory' => 'config', + ], +]; diff --git a/blog-api/public/index.php b/blog-api/public/index.php index bc508b5ed..fd3ded372 100644 --- a/blog-api/public/index.php +++ b/blog-api/public/index.php @@ -35,9 +35,16 @@ } // Run HTTP application runner -$runner = (new HttpApplicationRunner(dirname(__DIR__), $_ENV['YII_DEBUG'], $_ENV['YII_ENV'])) - ->withTemporaryErrorHandler(new ErrorHandler( - new Logger([new FileTarget(dirname(__DIR__) . '/runtime/logs/app.log')]), - new JsonRenderer(), - )); +$runner = (new HttpApplicationRunner( + rootPath: dirname(__DIR__), + debug: $_ENV['YII_DEBUG'], + checkEvents: $_ENV['YII_DEBUG'], + environment: $_ENV['YII_ENV'] +)) + ->withTemporaryErrorHandler( + new ErrorHandler( + new Logger([new FileTarget(dirname(__DIR__) . '/runtime/logs/app.log')]), + new JsonRenderer(), + ) + ); $runner->run(); diff --git a/blog-api/src/Auth/AuthController.php b/blog-api/src/Auth/AuthController.php index 5aa01a482..d28d20d52 100644 --- a/blog-api/src/Auth/AuthController.php +++ b/blog-api/src/Auth/AuthController.php @@ -42,13 +42,17 @@ public function __construct( * path="/auth/", * summary="Authenticate by params", * description="", + * * @OA\Response( * response="200", * description="Success", + * * @OA\JsonContent( * allOf={ + * * @OA\Schema(ref="#/components/schemas/Response"), * @OA\Schema( + * * @OA\Property( * property="data", * type="object", @@ -58,15 +62,20 @@ public function __construct( * }, * ) * ), + * * @OA\Response( * response="400", * description="Bad request", + * * @OA\JsonContent(ref="#/components/schemas/BadResponse") * ), + * * @OA\RequestBody( * required=true, + * * @OA\MediaType( * mediaType="application/json", + * * @OA\Schema(ref="#/components/schemas/AuthRequest"), * ), * ), @@ -93,14 +102,18 @@ public function login(AuthRequest $request): ResponseInterface * summary="Logout", * description="", * security={{"ApiKey": {}}}, + * * @OA\Response( * response="200", * description="Success", + * * @OA\JsonContent(ref="#/components/schemas/Response") * ), + * * @OA\Response( * response="400", * description="Bad request", + * * @OA\JsonContent(ref="#/components/schemas/BadResponse") * ), * ) diff --git a/blog-api/src/Auth/AuthRequest.php b/blog-api/src/Auth/AuthRequest.php index b6d3415b9..004967063 100644 --- a/blog-api/src/Auth/AuthRequest.php +++ b/blog-api/src/Auth/AuthRequest.php @@ -12,6 +12,7 @@ /** * @OA\Schema( * schema="AuthRequest", + * * @OA\Property(example="Opal1144", property="login", format="string"), * @OA\Property(example="Opal1144", property="password", format="string"), * ) diff --git a/blog-api/src/Blog/BlogController.php b/blog-api/src/Blog/BlogController.php index 13e272559..92c46baf0 100644 --- a/blog-api/src/Blog/BlogController.php +++ b/blog-api/src/Blog/BlogController.php @@ -17,7 +17,9 @@ * name="blog", * description="Blog" * ) + * * @OA\Parameter( + * * @OA\Schema( * type="int", * example="2" @@ -55,22 +57,29 @@ public function __construct( * path="/blog/", * summary="Returns paginated blog posts", * description="", + * * @OA\Parameter(ref="#/components/parameters/PageRequest"), + * * @OA\Response( * response="200", * description="Success", + * * @OA\JsonContent( * allOf={ + * * @OA\Schema(ref="#/components/schemas/Response"), * @OA\Schema( + * * @OA\Property( * property="data", * type="object", * @OA\Property( * property="posts", * type="array", + * * @OA\Items(ref="#/components/schemas/Post") * ), + * * @OA\Property( * property="paginator", * type="object", @@ -105,19 +114,25 @@ public function index(PaginatorFormatter $paginatorFormatter, #[Query('page')] i * path="/blog/{id}", * summary="Returns a post with a given ID", * description="", + * * @OA\Parameter( + * * @OA\Schema(type="int", example="2"), * in="path", * name="id", * parameter="id" * ), + * * @OA\Response( * response="200", * description="Success", + * * @OA\JsonContent( * allOf={ + * * @OA\Schema(ref="#/components/schemas/Response"), * @OA\Schema( + * * @OA\Property( * property="data", * type="object", @@ -131,13 +146,17 @@ public function index(PaginatorFormatter $paginatorFormatter, #[Query('page')] i * }, * ) * ), + * * @OA\Response( * response="404", * description="Not found", + * * @OA\JsonContent( * allOf={ + * * @OA\Schema(ref="#/components/schemas/BadResponse"), * @OA\Schema( + * * @OA\Property(property="error_message", example="Entity not found"), * @OA\Property(property="error_code", nullable=true, example=404) * ), @@ -164,17 +183,22 @@ public function view(#[Route('id')] int $id): Response * summary="Creates a blog post", * description="", * security={{"ApiKey": {}}}, + * * @OA\Response( * response="200", * description="Success", + * * @OA\JsonContent( * ref="#/components/schemas/Response" * ) * ), + * * @OA\RequestBody( * required=true, + * * @OA\MediaType( * mediaType="application/json", + * * @OA\Schema(ref="#/components/schemas/EditPostRequest"), * ), * ), @@ -197,23 +221,30 @@ public function create(EditPostRequest $postRequest, UserRequest $userRequest): * summary="Updates a blog post with a given ID", * description="", * security={{"ApiKey": {}}}, + * * @OA\Parameter( + * * @OA\Schema(type="int", example="2"), * in="path", * name="id", * parameter="id" * ), + * * @OA\Response( * response="200", * description="Success", + * * @OA\JsonContent( * ref="#/components/schemas/Response" * ) * ), + * * @OA\RequestBody( * required=true, + * * @OA\MediaType( * mediaType="application/json", + * * @OA\Schema(ref="#/components/schemas/EditPostRequest"), * ), * ) diff --git a/blog-api/src/Blog/EditPostRequest.php b/blog-api/src/Blog/EditPostRequest.php index 42de4c172..375e02ded 100644 --- a/blog-api/src/Blog/EditPostRequest.php +++ b/blog-api/src/Blog/EditPostRequest.php @@ -7,13 +7,14 @@ use OpenApi\Annotations as OA; use Yiisoft\RequestModel\RequestModel; use Yiisoft\Validator\Result; -use Yiisoft\Validator\Rule\HasLength; +use Yiisoft\Validator\Rule\Length; use Yiisoft\Validator\Rule\Required; use Yiisoft\Validator\RulesProviderInterface; /** * @OA\Schema( * schema="EditPostRequest", + * * @OA\Property(example="Title post", property="title", format="string"), * @OA\Property(example="Text post", property="text", format="string"), * @OA\Property(example=1, property="status", format="int"), @@ -46,11 +47,11 @@ public function getRules(): array return [ 'body.title' => [ new Required(), - new HasLength(min: 5, max: 255), + new Length(min: 5, max: 255), ], 'body.text' => [ new Required(), - new HasLength(min: 5, max: 1000), + new Length(min: 5, max: 1000), ], 'body.status' => [ new Required(), diff --git a/blog-api/src/Blog/PostFormatter.php b/blog-api/src/Blog/PostFormatter.php index 5363a0309..3193d4bc9 100644 --- a/blog-api/src/Blog/PostFormatter.php +++ b/blog-api/src/Blog/PostFormatter.php @@ -9,6 +9,7 @@ /** * @OA\Schema( * schema="Post", + * * @OA\Property(example="100", property="id", format="int"), * @OA\Property(example="Title", property="title", format="string"), * @OA\Property(example="Text", property="content", format="string"), diff --git a/blog-api/src/Dto/ApiResponseData.php b/blog-api/src/Dto/ApiResponseData.php index ba7492f48..65e85c9eb 100644 --- a/blog-api/src/Dto/ApiResponseData.php +++ b/blog-api/src/Dto/ApiResponseData.php @@ -15,6 +15,7 @@ * allOf={ * @OA\Schema(ref="#/components/schemas/Response"), * @OA\Schema( + * * @OA\Property( * property="status", * example="failed", diff --git a/blog-api/src/Formatter/PaginatorFormatter.php b/blog-api/src/Formatter/PaginatorFormatter.php index 84221d5c0..983c6eefe 100644 --- a/blog-api/src/Formatter/PaginatorFormatter.php +++ b/blog-api/src/Formatter/PaginatorFormatter.php @@ -10,6 +10,7 @@ /** * @OA\Schema( * schema="Paginator", + * * @OA\Property(example="10", property="pageSize", format="int"), * @OA\Property(example="1", property="currentPage", format="int"), * @OA\Property(example="3", property="totalPages", format="int"), diff --git a/blog-api/src/InfoController.php b/blog-api/src/InfoController.php index c02fe1d72..3ce6fafb5 100644 --- a/blog-api/src/InfoController.php +++ b/blog-api/src/InfoController.php @@ -22,13 +22,17 @@ public function __construct(private VersionProvider $versionProvider) * path="/", * summary="Returns info about the API", * description="", + * * @OA\Response( * response="200", * description="Success", + * * @OA\JsonContent( * allOf={ + * * @OA\Schema(ref="#/components/schemas/Response"), * @OA\Schema( + * * @OA\Property( * property="data", * type="object", diff --git a/blog-api/src/User/UserController.php b/blog-api/src/User/UserController.php index ee7ecf30c..4baea2f64 100644 --- a/blog-api/src/User/UserController.php +++ b/blog-api/src/User/UserController.php @@ -42,19 +42,24 @@ public function __construct( * summary="Returns paginated users", * description="", * security={{"ApiKey": {}}}, + * * @OA\Response( * response="200", * description="Success", + * * @OA\JsonContent( * allOf={ + * * @OA\Schema(ref="#/components/schemas/Response"), * @OA\Schema( + * * @OA\Property( * property="data", * type="object", * @OA\Property( * property="users", * type="array", + * * @OA\Items(ref="#/components/schemas/User") * ), * ), @@ -86,19 +91,25 @@ public function list(): ResponseInterface * summary="Returns a user with a given ID", * description="", * security={{"ApiKey": {}}}, + * * @OA\Parameter( + * * @OA\Schema(type="int", example="2"), * in="path", * name="id", * parameter="id" * ), + * * @OA\Response( * response="200", * description="Success", + * * @OA\JsonContent( * allOf={ + * * @OA\Schema(ref="#/components/schemas/Response"), * @OA\Schema( + * * @OA\Property( * property="data", * type="object", diff --git a/blog-api/src/User/UserFormatter.php b/blog-api/src/User/UserFormatter.php index 4b44e09af..115280f45 100644 --- a/blog-api/src/User/UserFormatter.php +++ b/blog-api/src/User/UserFormatter.php @@ -9,6 +9,7 @@ /** * @OA\Schema( * schema="User", + * * @OA\Property(example="UserName", property="login", format="string"), * @OA\Property(example="13.12.2020 00:04:20", property="created_at", format="string"), * ) diff --git a/blog-api/tests/Acceptance.suite.yml b/blog-api/tests/Acceptance.suite.yml index 42dc406ff..d88211108 100644 --- a/blog-api/tests/Acceptance.suite.yml +++ b/blog-api/tests/Acceptance.suite.yml @@ -7,7 +7,7 @@ extensions: modules: enabled: - REST: - url: http://127.0.0.1:8881 + url: http://127.0.0.1:8881%BASE_URL% depends: PhpBrowser - Db: dsn: 'sqlite:tests/Support/Data/database.db' diff --git a/blog-api/tests/Functional.suite.yml b/blog-api/tests/Functional.suite.yml index 289db8882..125f6c5bb 100644 --- a/blog-api/tests/Functional.suite.yml +++ b/blog-api/tests/Functional.suite.yml @@ -7,6 +7,6 @@ extensions: modules: enabled: - PhpBrowser: - url: http://127.0.0.1:8881 + url: http://127.0.0.1:8881%BASE_URL% - \App\Tests\Support\Helper\Functional step_decorators: ~ diff --git a/blog-api/tests/Functional/UserControllerTest.php b/blog-api/tests/Functional/IndexControllerTest.php similarity index 81% rename from blog-api/tests/Functional/UserControllerTest.php rename to blog-api/tests/Functional/IndexControllerTest.php index b18509cbf..781f79ecd 100644 --- a/blog-api/tests/Functional/UserControllerTest.php +++ b/blog-api/tests/Functional/IndexControllerTest.php @@ -8,7 +8,7 @@ use PHPUnit\Framework\TestCase; use Yiisoft\Yii\Testing\FunctionalTester; -final class UserControllerTest extends TestCase +final class IndexControllerTest extends TestCase { private ?FunctionalTester $tester; @@ -17,12 +17,12 @@ protected function setUp(): void $this->tester = new FunctionalTester(); } - public function testGetIndex() + public function testGetIndex(): void { $method = 'GET'; $url = '/'; - $this->tester->bootstrapApplication('web', dirname(__DIR__, 2)); + $this->tester->bootstrapApplication(dirname(__DIR__, 2)); $response = $this->tester->doRequest($method, $url); $this->assertEquals( @@ -36,12 +36,12 @@ public function testGetIndex() ); } - public function testGetIndexMockVersion() + public function testGetIndexMockVersion(): void { $method = 'GET'; $url = '/'; - $this->tester->bootstrapApplication('web', dirname(__DIR__, 2)); + $this->tester->bootstrapApplication(dirname(__DIR__, 2)); $this->tester->mockService(VersionProvider::class, new VersionProvider('3.0.0')); diff --git a/blog-api/tests/Support/Data/database.db b/blog-api/tests/Support/Data/database.db index 1ac562e36..e0fa3d1db 100644 Binary files a/blog-api/tests/Support/Data/database.db and b/blog-api/tests/Support/Data/database.db differ diff --git a/blog-api/yii b/blog-api/yii index 8d2bd2fa6..ae28a32ea 100755 --- a/blog-api/yii +++ b/blog-api/yii @@ -8,5 +8,10 @@ use Yiisoft\Yii\Runner\Console\ConsoleApplicationRunner; require_once __DIR__ . '/autoload.php'; // Run console application runner -$runner = new ConsoleApplicationRunner(__DIR__, $_ENV['YII_DEBUG'], $_ENV['YII_ENV']); +$runner = new ConsoleApplicationRunner( + rootPath: __DIR__, + debug: $_ENV['YII_DEBUG'], + checkEvents: $_ENV['YII_DEBUG'], + environment: $_ENV['YII_ENV'] +); $runner->run(); diff --git a/blog/.env.test b/blog/.env.test index 454ab1431..76b1f81af 100644 --- a/blog/.env.test +++ b/blog/.env.test @@ -1,3 +1,4 @@ YII_ENV=test -YII_DEBUG=false +YII_DEBUG=true SENTRY_DSN= +BASE_URL=/ diff --git a/blog/composer.json b/blog/composer.json index 90f0b4222..7fd7fec3e 100644 --- a/blog/composer.json +++ b/blog/composer.json @@ -25,69 +25,69 @@ "cycle/orm": "^2.0", "doctrine/collections": "^1.6", "fakerphp/faker": "^1.14", - "httpsoft/http-message": "^1.0.5", + "httpsoft/http-message": "^1.1", "php-http/guzzle7-adapter": "^1.0", "psr/container": "^2.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", + "psr/http-message": "^1.1|^2.0", "psr/http-server-handler": "^1.0", "psr/http-server-middleware": "^1.0", "psr/log": "^3.0", "symfony/console": "^6.0", "vlucas/phpdotenv": "^5.3", "yiisoft/access": "^1.0", - "yiisoft/aliases": "^2.0", - "yiisoft/assets": "^2.1", + "yiisoft/aliases": "^3.0", + "yiisoft/assets": "^4.0", "yiisoft/auth": "^3.0", - "yiisoft/cache": "^2.0", - "yiisoft/cache-file": "^2.0", + "yiisoft/cache": "^3.0", + "yiisoft/cache-file": "^3.0", "yiisoft/config": "^1.0", "yiisoft/cookies": "^1.2", - "yiisoft/csrf": "^1.2", + "yiisoft/csrf": "^2.0", "yiisoft/data": "^1.0", - "yiisoft/data-response": "^1.0", + "yiisoft/data-response": "^2.0", "yiisoft/definitions": "^3.0", "yiisoft/di": "^1.2", - "yiisoft/error-handler": "^2.0", + "yiisoft/error-handler": "^3.0", "yiisoft/factory": "^1.0", "yiisoft/form": "^1.0@dev", "yiisoft/html": "^3.0", "yiisoft/http": "^1.2", "yiisoft/injector": "^1.0", "yiisoft/log": "^2.0", - "yiisoft/log-target-file": "^2.0", + "yiisoft/log-target-file": "^3.0", "yiisoft/mailer": "^5.0", - "yiisoft/mailer-symfony": "^2.1", + "yiisoft/mailer-symfony": "^3.0", "yiisoft/rate-limiter": "dev-master", - "yiisoft/request-model": "dev-master", "yiisoft/rbac": "^1.0", "yiisoft/rbac-php": "^1.0", - "yiisoft/rbac-rules-container": "^1.1", - "yiisoft/router": "^2.1", - "yiisoft/router-fastroute": "^2.1", + "yiisoft/rbac-rules-container": "^2.0", + "yiisoft/request-model": "dev-master", + "yiisoft/router": "^3.0", + "yiisoft/router-fastroute": "^3.0", "yiisoft/security": "^1.0", - "yiisoft/session": "^1.0", - "yiisoft/translator": "^2.0", - "yiisoft/translator-message-php": "^1.1", - "yiisoft/user": "^1.0", - "yiisoft/validator": "3.0.x-dev", + "yiisoft/session": "^2.0", + "yiisoft/translator": "^3.0", + "yiisoft/translator-message-php": "^1.1.1", + "yiisoft/user": "^2.0", + "yiisoft/validator": "^1.0", "yiisoft/var-dumper": "^1.0", - "yiisoft/view": "^7.0", + "yiisoft/view": "^8.0", "yiisoft/widget": "^2.0", "yiisoft/yii-bootstrap5": "^3.0@dev", - "yiisoft/yii-console": "^1.0", + "yiisoft/yii-console": "^2.0", "yiisoft/yii-cycle": "dev-master", "yiisoft/yii-dataview": "^3.0@dev", "yiisoft/yii-debug": "^3.0@dev", "yiisoft/yii-debug-api": "^3.0@dev", - "yiisoft/yii-event": "^1.0", + "yiisoft/yii-event": "^2.0", "yiisoft/yii-http": "^1.0", - "yiisoft/yii-middleware": "dev-master", - "yiisoft/yii-runner-console": "^1.0", - "yiisoft/yii-runner-http": "^1.1", + "yiisoft/yii-middleware": "^1.0", + "yiisoft/yii-runner-console": "^2.0", + "yiisoft/yii-runner-http": "^2.0", "yiisoft/yii-sentry": "dev-master", - "yiisoft/yii-swagger": "^1.0", - "yiisoft/yii-view": "^5.0" + "yiisoft/yii-swagger": "^2.0", + "yiisoft/yii-view": "^6.0" }, "require-dev": { "codeception/c3": "^2.6", @@ -100,7 +100,7 @@ "roave/security-advisories": "dev-master", "spatie/phpunit-watcher": "^1.23", "vimeo/psalm": "^4.18", - "yiisoft/translator-extractor": "^1.1", + "yiisoft/translator-extractor": "^2.0", "yiisoft/yii-debug-viewer": "^3.0@dev", "yiisoft/yii-gii": "^3.0@dev", "yiisoft/yii-testing": "dev-master" @@ -110,6 +110,11 @@ "App\\": "src" } }, + "autoload-dev": { + "psr-4": { + "App\\Tests\\": "tests" + } + }, "scripts": { "serve": [ "Composer\\Config::disableProcessTimeout", @@ -129,82 +134,7 @@ "branch-alias": { "dev-master": "3.0.x-dev" }, - "config-plugin-options": { - "source-directory": "config" - }, - "config-plugin-environments": { - "dev": { - "params": [ - "test/params.php" - ] - }, - "prod": { - "params": [ - "test/params.php" - ] - }, - "test": { - "params": [ - "test/params.php" - ] - } - }, - "config-plugin": { - "common": "common/*.php", - "params": [ - "params.php", - "?params-local.php" - ], - "web": [ - "$common", - "web/*.php" - ], - "console": [ - "$common", - "console/*.php" - ], - "events": "events.php", - "events-web": [ - "$events", - "events-web.php" - ], - "events-console": [ - "$events", - "events-console.php" - ], - "providers": "providers.php", - "providers-web": [ - "$providers", - "providers-web.php" - ], - "providers-console": [ - "$providers", - "providers-console.php" - ], - "delegates": "delegates.php", - "delegates-web": [ - "$delegates", - "delegates-web.php" - ], - "delegates-console": [ - "$delegates", - "delegates-console.php" - ], - "routes": [ - "routes-backend.php", - "routes.php" - ], - "bootstrap": "bootstrap.php", - "bootstrap-web": [ - "$bootstrap", - "bootstrap-web.php" - ], - "bootstrap-console": [ - "$bootstrap", - "bootstrap-console.php" - ], - "widgets": "widgets.php" - }, + "config-plugin-file": "configuration.php", "installer-types": [ "npm-asset" ], @@ -222,7 +152,8 @@ "composer/installers": true, "composer/package-versions-deprecated": true, "infection/extension-installer": true, - "yiisoft/config": true + "yiisoft/config": true, + "php-http/discovery": false } }, "repositories": [ diff --git a/blog/config/bootstrap-console.php b/blog/config/bootstrap-console.php deleted file mode 100644 index 0dae23dee..000000000 --- a/blog/config/bootstrap-console.php +++ /dev/null @@ -1,5 +0,0 @@ -get(\Yiisoft\Router\UrlGeneratorInterface::class); - $urlGenerator->setUriPrefix($_ENV['BASE_URL']); - }, -]; diff --git a/blog-api/config/bootstrap-web.php b/blog/config/common/bootstrap.php similarity index 100% rename from blog-api/config/bootstrap-web.php rename to blog/config/common/bootstrap.php diff --git a/blog/config/common/cache.php b/blog/config/common/di/cache.php similarity index 100% rename from blog/config/common/cache.php rename to blog/config/common/di/cache.php diff --git a/blog/config/common/cycle.php b/blog/config/common/di/cycle.php similarity index 100% rename from blog/config/common/cycle.php rename to blog/config/common/di/cycle.php diff --git a/blog/config/common/logger.php b/blog/config/common/di/logger.php similarity index 100% rename from blog/config/common/logger.php rename to blog/config/common/di/logger.php diff --git a/blog/config/common/psr17.php b/blog/config/common/di/psr17.php similarity index 100% rename from blog/config/common/psr17.php rename to blog/config/common/di/psr17.php diff --git a/blog/config/common/rbac.php b/blog/config/common/di/rbac.php similarity index 100% rename from blog/config/common/rbac.php rename to blog/config/common/di/rbac.php diff --git a/blog/config/common/router.php b/blog/config/common/di/router.php similarity index 100% rename from blog/config/common/router.php rename to blog/config/common/di/router.php diff --git a/blog/config/common/sentry.php b/blog/config/common/di/sentry.php similarity index 100% rename from blog/config/common/sentry.php rename to blog/config/common/di/sentry.php diff --git a/blog/config/common/translator.php b/blog/config/common/di/translator.php similarity index 100% rename from blog/config/common/translator.php rename to blog/config/common/di/translator.php diff --git a/blog/config/common/validator.php b/blog/config/common/di/validator.php similarity index 100% rename from blog/config/common/validator.php rename to blog/config/common/di/validator.php diff --git a/blog/config/params.php b/blog/config/common/params.php similarity index 81% rename from blog/config/params.php rename to blog/config/common/params.php index af5fa3082..fe4e56c8a 100644 --- a/blog/config/params.php +++ b/blog/config/common/params.php @@ -9,53 +9,28 @@ use Cycle\Database\Config\SQLite\FileConnectionConfig; use Cycle\Database\Config\SQLiteDriverConfig; use Yiisoft\Assets\AssetManager; -use Yiisoft\Cookies\CookieMiddleware; use Yiisoft\Definitions\Reference; -use Yiisoft\ErrorHandler\Middleware\ErrorCatcher; use Yiisoft\Form\Field\SubmitButton; use Yiisoft\Router\CurrentRoute; -use Yiisoft\Router\Middleware\Router; use Yiisoft\Router\UrlGeneratorInterface; -use Yiisoft\Session\SessionMiddleware; use Yiisoft\Translator\TranslatorInterface; -use Yiisoft\User\Login\Cookie\CookieLoginMiddleware; -use Yiisoft\Yii\Console\Application; -use Yiisoft\Yii\Console\Command\Serve; use Yiisoft\Yii\Cycle\Schema\Conveyor\AttributedSchemaConveyor; use Yiisoft\Yii\Cycle\Schema\Provider\FromConveyorSchemaProvider; use Yiisoft\Yii\Cycle\Schema\Provider\PhpFileSchemaProvider; -use Yiisoft\Yii\Middleware\Locale; -use Yiisoft\Yii\Sentry\SentryMiddleware; use Yiisoft\Yii\View\CsrfViewInjection; return [ - 'locale' => [ - 'locales' => ['en' => 'en-US', 'ru' => 'ru-RU', 'id' => 'id-ID', 'sk' => 'sk-SK'], - 'ignoredRequests' => [ - '/debug**', - '/inspect**', - ], - ], 'mailer' => [ 'adminEmail' => 'admin@example.com', 'senderEmail' => 'sender@example.com', ], - 'middlewares' => [ - ErrorCatcher::class, - SentryMiddleware::class, - SessionMiddleware::class, - CookieMiddleware::class, - CookieLoginMiddleware::class, - Locale::class, - Router::class, - ], 'yiisoft/aliases' => [ 'aliases' => [ - '@root' => dirname(__DIR__), + '@root' => dirname(__DIR__, 2), '@assets' => '@root/public/assets', '@assetsUrl' => '@baseUrl/assets', - '@baseUrl' => $_ENV['BASE_URL'], + '@baseUrl' => '', '@messages' => '@resources/messages', '@npm' => '@root/node_modules', '@public' => '@root/public', @@ -129,21 +104,6 @@ ], ], - 'yiisoft/yii-console' => [ - 'name' => Application::NAME, - 'version' => Application::VERSION, - 'autoExit' => false, - 'commands' => [ - 'serve' => Serve::class, - 'user/create' => App\User\Console\CreateCommand::class, - 'user/assignRole' => App\User\Console\AssignRoleCommand::class, - 'fixture/add' => App\Command\Fixture\AddCommand::class, - 'fixture/schema/clear' => App\Command\Fixture\SchemaClearCommand::class, - 'router/list' => App\Command\Router\ListCommand::class, - 'translator/translate' => App\Command\Translation\TranslateCommand::class, - ], - ], - 'yiisoft/yii-cycle' => [ // DBAL config 'dbal' => [ diff --git a/blog/config/rbac-rules.php b/blog/config/common/rbac-rules.php similarity index 100% rename from blog/config/rbac-rules.php rename to blog/config/common/rbac-rules.php diff --git a/blog/config/routes-backend.php b/blog/config/common/routes/routes-backend.php similarity index 100% rename from blog/config/routes-backend.php rename to blog/config/common/routes/routes-backend.php diff --git a/blog/config/routes.php b/blog/config/common/routes/routes.php similarity index 97% rename from blog/config/routes.php rename to blog/config/common/routes/routes.php index d06a4a7a8..0d5156aec 100644 --- a/blog/config/routes.php +++ b/blog/config/common/routes/routes.php @@ -31,6 +31,7 @@ use Yiisoft\Router\UrlGeneratorInterface; use Yiisoft\Swagger\Middleware\SwaggerJson; use Yiisoft\Swagger\Middleware\SwaggerUi; +use Yiisoft\Yii\Middleware\CorsAllowAll; use Yiisoft\Yii\Middleware\HttpCache; use Yiisoft\Yii\RateLimiter\Counter; use Yiisoft\Yii\RateLimiter\LimitRequestsMiddleware; @@ -101,7 +102,7 @@ // Blog routes Group::create('/blog') ->routes( - // Index + // Index Route::get('[/page{page:\d+}]') ->middleware( fn (HttpCache $httpCache, PostRepository $postRepository) => $httpCache->withLastModified(function (ServerRequestInterface $request, $params) use ($postRepository) { @@ -144,7 +145,7 @@ // Archive Group::create('/archive') ->routes( - // Index page + // Index page Route::get('') ->action([ArchiveController::class, 'index']) ->name('blog/archive/index'), @@ -174,6 +175,7 @@ ->name('swagger/index'), Route::get('/openapi.json') ->middleware(FormatDataResponseAsJson::class) - ->action(SwaggerJson::class), + ->middleware(CorsAllowAll::class) + ->action([SwaggerJson::class, 'handle']), ), ]; diff --git a/blog/config/console/commands.php b/blog/config/console/commands.php new file mode 100644 index 000000000..61f564648 --- /dev/null +++ b/blog/config/console/commands.php @@ -0,0 +1,15 @@ + Serve::class, + 'user/create' => App\User\Console\CreateCommand::class, + 'user/assignRole' => App\User\Console\AssignRoleCommand::class, + 'fixture/add' => App\Command\Fixture\AddCommand::class, + 'fixture/schema/clear' => App\Command\Fixture\SchemaClearCommand::class, + 'router/list' => App\Command\Router\ListCommand::class, + 'translator/translate' => App\Command\Translation\TranslateCommand::class, +]; diff --git a/blog/config/console/translator-extractor.php b/blog/config/console/di/translator-extractor.php similarity index 100% rename from blog/config/console/translator-extractor.php rename to blog/config/console/di/translator-extractor.php diff --git a/blog/config/events-console.php b/blog/config/console/events.php similarity index 100% rename from blog/config/events-console.php rename to blog/config/console/events.php diff --git a/blog/config/console/params.php b/blog/config/console/params.php new file mode 100644 index 000000000..e21790626 --- /dev/null +++ b/blog/config/console/params.php @@ -0,0 +1,14 @@ + [ + 'name' => Application::NAME, + 'version' => Application::VERSION, + 'autoExit' => false, + 'commands' => require __DIR__ . '/commands.php', + ], +]; diff --git a/blog/config/delegates-console.php b/blog/config/delegates-console.php deleted file mode 100644 index 0dae23dee..000000000 --- a/blog/config/delegates-console.php +++ /dev/null @@ -1,5 +0,0 @@ - [ '__construct()' => [ - 'locales' => $params['locale']['locales'], - 'ignoredRequests' => $params['locale']['ignoredRequests'], + 'supportedLocales' => $params['locale']['locales'], + 'ignoredRequestUrlPatterns' => $params['locale']['ignoredRequests'], + ], + ], + Subfolder::class => [ + '__construct()' => [ + 'prefix' => !empty(trim($_ENV['BASE_URL'] ?? '', '/')) ? $_ENV['BASE_URL'] : null, ], ], ]; diff --git a/blog/config/web/auth.php b/blog/config/web/di/auth.php similarity index 100% rename from blog/config/web/auth.php rename to blog/config/web/di/auth.php diff --git a/blog/config/web/comment-service.php b/blog/config/web/di/comment-service.php similarity index 100% rename from blog/config/web/comment-service.php rename to blog/config/web/di/comment-service.php diff --git a/blog/config/web/contact-mailer.php b/blog/config/web/di/contact-mailer.php similarity index 100% rename from blog/config/web/contact-mailer.php rename to blog/config/web/di/contact-mailer.php diff --git a/blog/config/web/middleware-dispatcher.php b/blog/config/web/di/middleware-dispatcher.php similarity index 100% rename from blog/config/web/middleware-dispatcher.php rename to blog/config/web/di/middleware-dispatcher.php diff --git a/blog/config/web/rate-limit.php b/blog/config/web/di/rate-limit.php similarity index 100% rename from blog/config/web/rate-limit.php rename to blog/config/web/di/rate-limit.php diff --git a/blog/config/events-web.php b/blog/config/web/events.php similarity index 100% rename from blog/config/events-web.php rename to blog/config/web/events.php diff --git a/blog/config/web/params.php b/blog/config/web/params.php new file mode 100644 index 000000000..90d18da23 --- /dev/null +++ b/blog/config/web/params.php @@ -0,0 +1,33 @@ + [ + ErrorCatcher::class, + SentryMiddleware::class, + SessionMiddleware::class, + CookieMiddleware::class, + CookieLoginMiddleware::class, + Subfolder::class, + Locale::class, + Router::class, + ], + + 'locale' => [ + 'locales' => ['en' => 'en-US', 'ru' => 'ru-RU', 'id' => 'id-ID', 'sk' => 'sk-SK'], + 'ignoredRequests' => [ + '/debug**', + '/inspect**', + ], + ], +]; diff --git a/blog/config/widgets.php b/blog/config/widgets.php deleted file mode 100644 index 0dae23dee..000000000 --- a/blog/config/widgets.php +++ /dev/null @@ -1,5 +0,0 @@ - [ + 'params' => [ + 'common/params.php', + ], + 'params-web' => [ + '$params', + 'web/params.php', + ], + 'params-console' => [ + '$params', + 'console/params.php', + ], + 'di' => 'common/di/*.php', + 'di-web' => [ + '$di', + 'web/di/*.php', + ], + 'di-console' => '$di', + 'di-providers' => [], + 'di-providers-web' => [ + '$di-providers', + ], + 'di-providers-console' => [ + '$di-providers', + ], + 'di-delegates' => [], + 'di-delegates-web' => [ + '$di-delegates', + ], + 'di-delegates-console' => [ + '$di-delegates', + ], + 'events' => [], + 'events-web' => [ + '$events', + 'web/events.php', + ], + 'events-console' => [ + '$events', + 'console/events.php', + ], + 'routes' => [ + 'common/routes/*.php', + ], + 'bootstrap' => [ + 'common/bootstrap.php', + ], + 'bootstrap-web' => [ + '$bootstrap', + ], + 'bootstrap-console' => [ + '$bootstrap', + ], + ], + 'config-plugin-environments' => [ + 'dev' => [ + 'params' => [ + 'environments/dev/params.php', + ], + ], + 'prod' => [ + 'params' => [ + 'environments/prod/params.php', + ], + ], + 'test' => [ + 'params' => [ + 'environments/test/params.php', + ], + ], + ], + 'config-plugin-options' => [ + 'source-directory' => 'config', + ], +]; diff --git a/blog/public/index.php b/blog/public/index.php index 1df961e32..beb3659fc 100644 --- a/blog/public/index.php +++ b/blog/public/index.php @@ -31,5 +31,10 @@ require_once dirname(__DIR__) . '/autoload.php'; // Run HTTP application runner -$runner = new HttpApplicationRunner(dirname(__DIR__), $_ENV['YII_DEBUG'], environment: $_ENV['YII_ENV']); +$runner = new HttpApplicationRunner( + rootPath: dirname(__DIR__), + debug: $_ENV['YII_DEBUG'], + checkEvents: $_ENV['YII_DEBUG'], + environment: $_ENV['YII_ENV'] +); $runner->run(); diff --git a/blog/src/Auth/Form/LoginForm.php b/blog/src/Auth/Form/LoginForm.php index 98e49308d..985c9d529 100644 --- a/blog/src/Auth/Form/LoginForm.php +++ b/blog/src/Auth/Form/LoginForm.php @@ -10,8 +10,9 @@ use Yiisoft\Validator\Result; use Yiisoft\Validator\Rule\Callback; use Yiisoft\Validator\Rule\Required; +use Yiisoft\Validator\RulesProviderInterface; -final class LoginForm extends FormModel +final class LoginForm extends FormModel implements RulesProviderInterface { private string $login = ''; private string $password = ''; diff --git a/blog/src/Auth/Form/SignupForm.php b/blog/src/Auth/Form/SignupForm.php index 9763f726c..30984ef2a 100644 --- a/blog/src/Auth/Form/SignupForm.php +++ b/blog/src/Auth/Form/SignupForm.php @@ -10,11 +10,12 @@ use Yiisoft\Translator\TranslatorInterface; use Yiisoft\Validator\Result; use Yiisoft\Validator\Rule\Equal; -use Yiisoft\Validator\Rule\HasLength; +use Yiisoft\Validator\Rule\Length; use Yiisoft\Validator\Rule\Required; +use Yiisoft\Validator\RulesProviderInterface; use Yiisoft\Validator\ValidatorInterface; -final class SignupForm extends FormModel +final class SignupForm extends FormModel implements RulesProviderInterface { private string $login = ''; private string $password = ''; @@ -69,7 +70,7 @@ public function getRules(): array return [ 'login' => [ new Required(), - new HasLength(min: 1, max: 48, skipOnError: true), + new Length(min: 1, max: 48, skipOnError: true), function ($value): Result { $result = new Result(); if ($this->userRepository->findByLogin($value) !== null) { @@ -81,7 +82,7 @@ function ($value): Result { ], 'password' => [ new Required(), - new HasLength(min: 8), + new Length(min: 8), ], 'passwordVerify' => [ new Required(), diff --git a/blog/src/Contact/ContactForm.php b/blog/src/Contact/ContactForm.php index 182570215..ec76a96d0 100644 --- a/blog/src/Contact/ContactForm.php +++ b/blog/src/Contact/ContactForm.php @@ -7,8 +7,9 @@ use Yiisoft\Form\FormModel; use Yiisoft\Validator\Rule\Email; use Yiisoft\Validator\Rule\Required; +use Yiisoft\Validator\RulesProviderInterface; -final class ContactForm extends FormModel +final class ContactForm extends FormModel implements RulesProviderInterface { private string $name = ''; private string $email = ''; diff --git a/blog/src/Controller/Actions/ApiInfo.php b/blog/src/Controller/Actions/ApiInfo.php index b2aad8e2e..dc83f1c06 100644 --- a/blog/src/Controller/Actions/ApiInfo.php +++ b/blog/src/Controller/Actions/ApiInfo.php @@ -26,6 +26,7 @@ public function __construct(DataResponseFactoryInterface $responseFactory) /** * @OA\Get( * path="/api/info/v2", + * * @OA\Response(response="200", description="Get api version") * ) */ diff --git a/blog/src/User/Controller/ApiUserController.php b/blog/src/User/Controller/ApiUserController.php index 1f3bb769a..9f0c4e55f 100644 --- a/blog/src/User/Controller/ApiUserController.php +++ b/blog/src/User/Controller/ApiUserController.php @@ -28,6 +28,7 @@ public function __construct(private DataResponseFactoryInterface $responseFactor * @OA\Get( * path="/api/user", * tags={"user"}, + * * @OA\Response(response="200", description="Get users list") * ) */ @@ -52,12 +53,15 @@ public function index(UserRepository $userRepository): ResponseInterface * @OA\Get( * path="/api/user/{login}", * tags={"user"}, + * * @OA\Parameter( + * * @OA\Schema(type="string"), * in="path", * name="login", * parameter="login" * ), + * * @OA\Response(response="200", description="Get user info") * ) */ diff --git a/blog/tests/Acceptance.suite.yml b/blog/tests/Acceptance.suite.yml index 94370b4a5..d4c578c4c 100644 --- a/blog/tests/Acceptance.suite.yml +++ b/blog/tests/Acceptance.suite.yml @@ -7,6 +7,6 @@ extensions: modules: enabled: - PhpBrowser: - url: http://127.0.0.1:8881 + url: http://127.0.0.1:8881%BASE_URL% - \App\Tests\Support\Helper\Acceptance step_decorators: ~ diff --git a/blog/tests/Functional.suite.yml b/blog/tests/Functional.suite.yml index 289db8882..125f6c5bb 100644 --- a/blog/tests/Functional.suite.yml +++ b/blog/tests/Functional.suite.yml @@ -7,6 +7,6 @@ extensions: modules: enabled: - PhpBrowser: - url: http://127.0.0.1:8881 + url: http://127.0.0.1:8881%BASE_URL% - \App\Tests\Support\Helper\Functional step_decorators: ~ diff --git a/blog/tests/Functional/EventListenerConfigurationTest.php b/blog/tests/Functional/EventListenerConfigurationTest.php index 0e5f3fc62..f752ca32a 100644 --- a/blog/tests/Functional/EventListenerConfigurationTest.php +++ b/blog/tests/Functional/EventListenerConfigurationTest.php @@ -4,26 +4,39 @@ namespace App\Tests\Functional; -use function dirname; +use Yiisoft\Config\Config; use PHPUnit\Framework\TestCase; -use Psr\Container\ContainerInterface; use Yiisoft\Config\ConfigPaths; +use Yiisoft\Config\Modifier\RecursiveMerge; +use Yiisoft\Config\Modifier\ReverseMerge; use Yiisoft\Di\Container; use Yiisoft\Di\ContainerConfig; use Yiisoft\Yii\Event\ListenerConfigurationChecker; -use Yiisoft\Yii\Runner\ConfigFactory; class EventListenerConfigurationTest extends TestCase { public function testConsoleListenerConfiguration(): void { - $config = ConfigFactory::create(new ConfigPaths(dirname(__DIR__, 2), 'config'), $_ENV['YII_ENV']); + $config = new Config( + new ConfigPaths(dirname(__DIR__, 2), 'config'), + $_ENV['YII_ENV'], + [ + ReverseMerge::groups('events', 'events-web', 'events-console'), + RecursiveMerge::groups('params', 'params-web', 'params-console', 'events', 'events-web', 'events-console'), + ], + 'params', + ); + + $container = new Container( + ContainerConfig::create() + ->withDefinitions($config->get('di-console')) + ->withProviders($config->get('di-providers-console')) + ); - $containerConfig = ContainerConfig::create() - ->withDefinitions($config->get('console')); - $container = (new Container($containerConfig))->get(ContainerInterface::class); $checker = $container->get(ListenerConfigurationChecker::class); + $checker->check($config->get('events-console')); + $checker->check($config->get('events-web')); self::assertInstanceOf(ListenerConfigurationChecker::class, $checker); } diff --git a/blog/tests/Functional/IndexControllerTest.php b/blog/tests/Functional/IndexControllerTest.php index a66431881..4da8e7d68 100644 --- a/blog/tests/Functional/IndexControllerTest.php +++ b/blog/tests/Functional/IndexControllerTest.php @@ -21,7 +21,7 @@ public function testGetIndex() $method = 'GET'; $url = '/'; - $this->tester->bootstrapApplication('web', dirname(__DIR__, 2)); + $this->tester->bootstrapApplication(dirname(__DIR__, 2)); $response = $this->tester->doRequest($method, $url); $this->assertStringContainsString('Hello, everyone', $response->getContent()); diff --git a/blog/yii b/blog/yii index 0289ec8b7..ae28a32ea 100755 --- a/blog/yii +++ b/blog/yii @@ -8,5 +8,10 @@ use Yiisoft\Yii\Runner\Console\ConsoleApplicationRunner; require_once __DIR__ . '/autoload.php'; // Run console application runner -$runner = new ConsoleApplicationRunner(__DIR__, $_ENV['YII_DEBUG'], environment: $_ENV['YII_ENV']); +$runner = new ConsoleApplicationRunner( + rootPath: __DIR__, + debug: $_ENV['YII_DEBUG'], + checkEvents: $_ENV['YII_DEBUG'], + environment: $_ENV['YII_ENV'] +); $runner->run();