diff --git a/.env.example b/.env.example index d9f4297..0e9db3a 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -APP_NAME=Laravel +APP_NAME="News Aggregator" APP_ENV=dev APP_KEY=base64:pz1gU5Un7JAHTnHHhoS80lh/2GGTf2JufhTFKfUOO0Q= APP_DEBUG=true diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index b2d274c..0c9a4fd 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -15,4 +15,4 @@ jobs: - uses: actions/checkout@v4 - name: PHPStan - run: make phpstan + run: make up-php & make phpstan diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index ce35d17..00b2244 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -15,4 +15,4 @@ jobs: - uses: actions/checkout@v4 - name: Test - run: make test + run: make up-php & make test diff --git a/Dockerfile b/Dockerfile index 43d2335..28bfd62 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,6 @@ FROM php:8.4-fpm # Install dependencies RUN apt-get update && apt-get install -y \ - git \ unzip \ libpq-dev \ librabbitmq-dev \ diff --git a/Makefile b/Makefile index 036cbac..cdad2a1 100644 --- a/Makefile +++ b/Makefile @@ -1,27 +1,33 @@ default: setup -setup: copy-env up install migration seed test +setup: copy-env up install migration seed test up-workers copy-env: cp .env.example .env install: - docker compose run --rm php sh -c "composer install" + docker compose exec php sh -c "composer install" migration: - docker compose run --rm php sh -c "php artisan migrate" + docker compose exec php sh -c "php artisan migrate" seed: - docker compose run --rm php sh -c "php artisan db:seed" + docker compose exec php sh -c "php artisan db:seed" up: docker compose up -d +up-php: + docker compose up --no-deps -d php + +up-workers: + docker compose up -d queue-worker cron + test: - docker compose run --no-deps --rm php sh -c "touch database/database.sqlite && composer install && composer test" + docker compose exec php sh -c "touch database/database.sqlite && composer install && composer test" phpstan: - docker compose run --no-deps --rm php sh -c "composer install && composer phpstan" + docker compose exec php sh -c "composer install && composer phpstan" fetch_articles: - docker compose run --no-deps --rm php sh -c "php artisan articles:fetch" + docker compose exec php sh -c "php artisan articles:fetch" diff --git a/README.md b/README.md index 1a4c26b..f637f25 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,33 @@ -
- - - -## About Laravel - -Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as: - -- [Simple, fast routing engine](https://laravel.com/docs/routing). -- [Powerful dependency injection container](https://laravel.com/docs/container). -- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage. -- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent). -- Database agnostic [schema migrations](https://laravel.com/docs/migrations). -- [Robust background job processing](https://laravel.com/docs/queues). -- [Real-time event broadcasting](https://laravel.com/docs/broadcasting). - -Laravel is accessible, powerful, and provides tools required for large, robust applications. - -## Learning Laravel - -Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. - -You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch. - -If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library. - -## Laravel Sponsors - -We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com). - -### Premium Partners - -- **[Vehikl](https://vehikl.com/)** -- **[Tighten Co.](https://tighten.co)** -- **[WebReinvent](https://webreinvent.com/)** -- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)** -- **[64 Robots](https://64robots.com)** -- **[Curotec](https://www.curotec.com/services/technologies/laravel/)** -- **[Cyber-Duck](https://cyber-duck.co.uk)** -- **[DevSquad](https://devsquad.com/hire-laravel-developers)** -- **[Jump24](https://jump24.co.uk)** -- **[Redberry](https://redberry.international/laravel/)** -- **[Active Logic](https://activelogic.com)** -- **[byte5](https://byte5.de)** -- **[OP.GG](https://op.gg)** - -## Contributing - -Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). - -## Code of Conduct - -In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). - -## Security Vulnerabilities - -If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed. - -## License - -The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). +### Setup +```sh +make +``` + +#### Manually Fetch Articles +##### Articles are fetched automatically every minute, so you don't need to do this +```sh +make fetch_articles +``` + +#### Api documentation - Swagger +http://localhost:8080/api/documentation + +Default User credentials: +```log +test@example.com +password +``` + +- get token from `/api/login` endpoint +- click on `Authorize` button on top right corner +- paste the token in the input box with `Bearer ` prefix + +#### Run tests +```sh +make test +``` + +#### Run phpstan +```sh +make phpstan +``` diff --git a/app/Http/Controllers/Api/ArticlesController.php b/app/Http/Controllers/Api/ArticlesController.php index d2fc867..2de5f30 100644 --- a/app/Http/Controllers/Api/ArticlesController.php +++ b/app/Http/Controllers/Api/ArticlesController.php @@ -4,10 +4,8 @@ namespace App\Http\Controllers\Api; -use App\Http\Controllers\Controller; use App\Http\Requests\Api\GetArticlesRequest; use App\Http\Resources\ArticleResource; -use App\Models\Article; use App\UseCase\GetArticles\GetArticlesUseCase; use App\UseCase\GetArticles\RequestModel; use DateMalformedStringException; @@ -15,15 +13,62 @@ use Domain\Exception\ExternalException; use Domain\Repository\ArticleRepositoryInterface; use Illuminate\Http\Resources\Json\JsonResource; -use Illuminate\Http\Resources\Json\ResourceCollection; use Ramsey\Uuid\Uuid; +use OpenApi\Attributes as OA; -class ArticlesController extends Controller +class ArticlesController extends BaseApiController { /** * @throws DateMalformedStringException * @throws ExternalException */ + #[OA\PathItem( + path: '/api/articles', + get: new OA\Get( + security: [['sanctum' => []]], + tags: [ 'Articles'], + parameters: [ + new OA\Parameter(name: 'page', in: 'query', required: true), + new OA\Parameter(name: 'per_page', in: 'query', required: true), + new OA\Parameter(name: 'search', in: 'query'), + new OA\Parameter(name: 'date_from', in: 'query'), + new OA\Parameter(name: 'category_id', in: 'query'), + new OA\Parameter(name: 'source_id', in: 'query'), + ], + responses: [ + new OA\Response( + response: 200, + description: 'Successful operation', + content: new OA\MediaType( + mediaType: 'application/json', + schema: new OA\Schema( + properties: [ + new OA\Property( + property: 'data', + properties: [ + new OA\Property( + property: 'meta', + properties: [], + type: 'object', + ), + new OA\Property( + property: 'records', + type: 'array', + items: new OA\Items( + ref: '#/components/schemas/ArticleResource', + ), + ), + ], + type: 'object', + ), + ], + type: 'object', + ), + ), + ), + ], + ), + )] public function index(GetArticlesRequest $request, GetArticlesUseCase $useCase): JsonResource { $responseModel = $useCase(new RequestModel( @@ -50,6 +95,26 @@ public function index(GetArticlesRequest $request, GetArticlesUseCase $useCase): ]); } + #[OA\PathItem( + path: '/api/articles/{id}', + get: new OA\Get( + security: [['sanctum' => []]], + tags: [ 'Articles'], + parameters: [ + new OA\Parameter(name: 'id', in: 'path', required: true), + ], + responses: [ + new OA\Response( + response: 200, + description: 'Successful operation', + content: new OA\MediaType( + mediaType: 'application/json', + schema: new OA\Schema(ref: '#/components/schemas/ArticleResource'), + ), + ), + ], + ), + )] public function show(string $id, ArticleRepositoryInterface $articleRepository): JsonResource { $article = $articleRepository->find(Uuid::fromString($id)); diff --git a/app/Http/Controllers/Api/AuthController.php b/app/Http/Controllers/Api/AuthController.php index fa25155..4d34416 100644 --- a/app/Http/Controllers/Api/AuthController.php +++ b/app/Http/Controllers/Api/AuthController.php @@ -4,15 +4,41 @@ namespace App\Http\Controllers\Api; -use App\Http\Controllers\Controller; use App\Http\Requests\Api\LoginRequest; use App\Models\User; use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Support\Facades\Hash; use Illuminate\Validation\ValidationException; +use OpenApi\Attributes as OA; -class AuthController extends Controller +class AuthController extends BaseApiController { + /** + * @throws ValidationException + */ + #[OA\PathItem( + path: '/api/login', + post: new OA\Post( + requestBody: new OA\RequestBody( + content: new OA\MediaType( + mediaType: 'multipart/form-data', + schema: new OA\Schema(ref: '#/components/schemas/LoginRequest'), + ) + ), + tags: [ 'Auth'], + responses: [ + new OA\Response( + response: 200, + description: 'Successful login', + content: new OA\JsonContent( + properties: [ + new OA\Property(property: 'token', type: 'string'), + ], + ) + ), + ], + ), + )] /** * @throws ValidationException */ diff --git a/app/Http/Controllers/Api/BaseApiController.php b/app/Http/Controllers/Api/BaseApiController.php new file mode 100644 index 0000000..b9d68d3 --- /dev/null +++ b/app/Http/Controllers/Api/BaseApiController.php @@ -0,0 +1,19 @@ +with(['author', 'source', 'category']) ->when($param->sourceId, fn ($q, $sourceId) => $q->where('source_id', $sourceId)) ->when($param->categoryId, fn ($q, $categoryId) => $q->where('category_id', $categoryId)) + ->when($param->search, fn ($q, $search) => $q->where('title', 'like', "%$search%")) ->paginate( perPage: $param->perPage, page: $param->page, diff --git a/app/Services/ArticleProviders/NewsApi/Dto/ArticleResponseDto.php b/app/Services/ArticleProviders/NewsApi/Dto/ArticleResponseDto.php index d80cf3f..1dfdef9 100644 --- a/app/Services/ArticleProviders/NewsApi/Dto/ArticleResponseDto.php +++ b/app/Services/ArticleProviders/NewsApi/Dto/ArticleResponseDto.php @@ -25,13 +25,13 @@ public static function fromPayload(array $payload): self { return new self( source: SourceResponseDto::fromPayload($payload[ 'source']), - title: $payload[ 'title'], - description: $payload[ 'description'], - url: $payload[ 'url'], - publishedAt: $payload[ 'publishedAt'], - content: $payload[ 'content'], - author: $payload[ 'author'], - urlToImage: $payload[ 'urlToImage'], + title: (string) $payload['title'], + description: (string) $payload['description'], + url: $payload['url'], + publishedAt: $payload['publishedAt'], + content: (string) $payload['content'], + author: $payload['author'], + urlToImage: $payload['urlToImage'], ); } } diff --git a/compose.yaml b/compose.yaml index 6a01cf0..4180842 100644 --- a/compose.yaml +++ b/compose.yaml @@ -26,7 +26,7 @@ services: - "9000" - "9003" - worker: + queue-worker: build: context: . dockerfile: Dockerfile @@ -38,6 +38,17 @@ services: depends_on: - database + cron: + build: + context: . + dockerfile: cron.Dockerfile + environment: + APP_ENV: "${APP_ENV}" + volumes: + - ./storage/logs:/var/www/html/storage/logs:rw + depends_on: + - database + web: image: nginx:alpine ports: diff --git a/composer.json b/composer.json index 6d3d055..2dc69d5 100644 --- a/composer.json +++ b/composer.json @@ -9,6 +9,7 @@ "license": "MIT", "require": { "php": "^8.4", + "darkaonline/l5-swagger": "^8.6", "laravel/framework": "^11.31", "laravel/sanctum": "^4.0", "laravel/tinker": "^2.9" diff --git a/composer.lock b/composer.lock index e7502a5..5fc13b6 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": "6531dda2ec9a3f14b59b5b8473d2fa0a", + "content-hash": "0fd64d62b8ccb85c82b1e75d2ef449c2", "packages": [ { "name": "brick/math", @@ -135,6 +135,86 @@ ], "time": "2024-02-09T16:56:22+00:00" }, + { + "name": "darkaonline/l5-swagger", + "version": "8.6.3", + "source": { + "type": "git", + "url": "https://github.com/DarkaOnLine/L5-Swagger.git", + "reference": "b37695804b786c04ab4077ceb6c0f2907ccd0153" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DarkaOnLine/L5-Swagger/zipball/b37695804b786c04ab4077ceb6c0f2907ccd0153", + "reference": "b37695804b786c04ab4077ceb6c0f2907ccd0153", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0 || ^2.0", + "ext-json": "*", + "laravel/framework": "^11.0 || ^10.0 || ^9.0 || >=8.40.0 || ^7.0", + "php": "^7.2 || ^8.0", + "swagger-api/swagger-ui": "^3.0 || >=4.1.3", + "symfony/yaml": "^5.0 || ^6.0 || ^7.0", + "zircote/swagger-php": "^3.2.0 || ^4.0.0" + }, + "require-dev": { + "mockery/mockery": "1.*", + "orchestra/testbench": "^9.0 || ^8.0 || 7.* || ^6.15 || 5.*", + "php-coveralls/php-coveralls": "^2.0", + "phpunit/phpunit": "^11.0 || ^10.0 || ^9.5" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "L5Swagger": "L5Swagger\\L5SwaggerFacade" + }, + "providers": [ + "L5Swagger\\L5SwaggerServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "L5Swagger\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Darius Matulionis", + "email": "darius@matulionis.lt" + } + ], + "description": "OpenApi or Swagger integration to Laravel", + "keywords": [ + "api", + "documentation", + "laravel", + "openapi", + "specification", + "swagger", + "ui" + ], + "support": { + "issues": "https://github.com/DarkaOnLine/L5-Swagger/issues", + "source": "https://github.com/DarkaOnLine/L5-Swagger/tree/8.6.3" + }, + "funding": [ + { + "url": "https://github.com/DarkaOnLine", + "type": "github" + } + ], + "time": "2024-10-28T06:29:43+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.3", @@ -210,6 +290,82 @@ }, "time": "2024-07-08T12:26:09+00:00" }, + { + "name": "doctrine/annotations", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/901c2ee5d26eb64ff43c47976e114bf00843acf7", + "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2 || ^3", + "ext-tokenizer": "*", + "php": "^7.2 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^2.0", + "doctrine/coding-standard": "^10", + "phpstan/phpstan": "^1.10.28", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "symfony/cache": "^5.4 || ^6.4 || ^7", + "vimeo/psalm": "^4.30 || ^5.14" + }, + "suggest": { + "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/2.0.2" + }, + "time": "2024-09-05T10:17:24+00:00" + }, { "name": "doctrine/inflector", "version": "2.0.10", @@ -2646,6 +2802,55 @@ ], "time": "2024-07-20T21:41:07+00:00" }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, { "name": "psr/clock", "version": "1.0.0", @@ -3362,6 +3567,67 @@ ], "time": "2024-04-27T21:32:50+00:00" }, + { + "name": "swagger-api/swagger-ui", + "version": "v5.18.2", + "source": { + "type": "git", + "url": "https://github.com/swagger-api/swagger-ui.git", + "reference": "3c7e281d97fd3e70b25f7ff4a001eabd56e375d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swagger-api/swagger-ui/zipball/3c7e281d97fd3e70b25f7ff4a001eabd56e375d7", + "reference": "3c7e281d97fd3e70b25f7ff4a001eabd56e375d7", + "shasum": "" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Anna Bodnia", + "email": "anna.bodnia@gmail.com" + }, + { + "name": "Buu Nguyen", + "email": "buunguyen@gmail.com" + }, + { + "name": "Josh Ponelat", + "email": "jponelat@gmail.com" + }, + { + "name": "Kyle Shockey", + "email": "kyleshockey1@gmail.com" + }, + { + "name": "Robert Barnwell", + "email": "robert@robertismy.name" + }, + { + "name": "Sahar Jafari", + "email": "shr.jafari@gmail.com" + } + ], + "description": " Swagger UI is a collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.", + "homepage": "http://swagger.io", + "keywords": [ + "api", + "documentation", + "openapi", + "specification", + "swagger", + "ui" + ], + "support": { + "issues": "https://github.com/swagger-api/swagger-ui/issues", + "source": "https://github.com/swagger-api/swagger-ui/tree/v5.18.2" + }, + "time": "2024-11-07T14:02:16+00:00" + }, { "name": "symfony/clock", "version": "v7.2.0", @@ -5590,6 +5856,78 @@ ], "time": "2024-11-08T15:48:14+00:00" }, + { + "name": "symfony/yaml", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "099581e99f557e9f16b43c5916c26380b54abb22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/099581e99f557e9f16b43c5916c26380b54abb22", + "reference": "099581e99f557e9f16b43c5916c26380b54abb22", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.2.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": "2024-10-23T06:56:12+00:00" + }, { "name": "tijsverkoyen/css-to-inline-styles", "version": "v2.3.0", @@ -5860,6 +6198,87 @@ "source": "https://github.com/webmozarts/assert/tree/1.11.0" }, "time": "2022-06-03T18:03:27+00:00" + }, + { + "name": "zircote/swagger-php", + "version": "4.11.1", + "source": { + "type": "git", + "url": "https://github.com/zircote/swagger-php.git", + "reference": "7df10e8ec47db07c031db317a25bef962b4e5de1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/7df10e8ec47db07c031db317a25bef962b4e5de1", + "reference": "7df10e8ec47db07c031db317a25bef962b4e5de1", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.2", + "psr/log": "^1.1 || ^2.0 || ^3.0", + "symfony/deprecation-contracts": "^2 || ^3", + "symfony/finder": ">=2.2", + "symfony/yaml": ">=3.3" + }, + "require-dev": { + "composer/package-versions-deprecated": "^1.11", + "doctrine/annotations": "^1.7 || ^2.0", + "friendsofphp/php-cs-fixer": "^2.17 || 3.62.0", + "phpstan/phpstan": "^1.6", + "phpunit/phpunit": ">=8", + "vimeo/psalm": "^4.23" + }, + "suggest": { + "doctrine/annotations": "^1.7 || ^2.0" + }, + "bin": [ + "bin/openapi" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "OpenApi\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Robert Allen", + "email": "zircote@gmail.com" + }, + { + "name": "Bob Fanger", + "email": "bfanger@gmail.com", + "homepage": "https://bfanger.nl" + }, + { + "name": "Martin Rademacher", + "email": "mano@radebatz.net", + "homepage": "https://radebatz.net" + } + ], + "description": "swagger-php - Generate interactive documentation for your RESTful API using phpdoc annotations", + "homepage": "https://github.com/zircote/swagger-php/", + "keywords": [ + "api", + "json", + "rest", + "service discovery" + ], + "support": { + "issues": "https://github.com/zircote/swagger-php/issues", + "source": "https://github.com/zircote/swagger-php/tree/4.11.1" + }, + "time": "2024-10-15T19:20:02+00:00" } ], "packages-dev": [ diff --git a/config/l5-swagger.php b/config/l5-swagger.php new file mode 100644 index 0000000..a560054 --- /dev/null +++ b/config/l5-swagger.php @@ -0,0 +1,318 @@ + 'default', + 'documentations' => [ + 'default' => [ + 'api' => [ + 'title' => 'L5 Swagger UI', + ], + + 'routes' => [ + /* + * Route for accessing api documentation interface + */ + 'api' => 'api/documentation', + ], + 'paths' => [ + /* + * Edit to include full URL in ui for assets + */ + 'use_absolute_path' => env('L5_SWAGGER_USE_ABSOLUTE_PATH', true), + + /* + * Edit to set path where swagger ui assets should be stored + */ + 'swagger_ui_assets_path' => env('L5_SWAGGER_UI_ASSETS_PATH', 'vendor/swagger-api/swagger-ui/dist/'), + + /* + * File name of the generated json documentation file + */ + 'docs_json' => 'api-docs.json', + + /* + * File name of the generated YAML documentation file + */ + 'docs_yaml' => 'api-docs.yaml', + + /* + * Set this to `json` or `yaml` to determine which documentation file to use in UI + */ + 'format_to_use_for_docs' => env('L5_FORMAT_TO_USE_FOR_DOCS', 'json'), + + /* + * Absolute paths to directory containing the swagger annotations are stored. + */ + 'annotations' => [ + base_path('app'), + ], + ], + ], + ], + 'defaults' => [ + 'routes' => [ + /* + * Route for accessing parsed swagger annotations. + */ + 'docs' => 'docs', + + /* + * Route for Oauth2 authentication callback. + */ + 'oauth2_callback' => 'api/oauth2-callback', + + /* + * Middleware allows to prevent unexpected access to API documentation + */ + 'middleware' => [ + 'api' => [], + 'asset' => [], + 'docs' => [], + 'oauth2_callback' => [], + ], + + /* + * Route Group options + */ + 'group_options' => [], + ], + + 'paths' => [ + /* + * Absolute path to location where parsed annotations will be stored + */ + 'docs' => storage_path('api-docs'), + + /* + * Absolute path to directory where to export views + */ + 'views' => base_path('resources/views/vendor/l5-swagger'), + + /* + * Edit to set the api's base path + */ + 'base' => env('L5_SWAGGER_BASE_PATH', null), + + /* + * Absolute path to directories that should be excluded from scanning + * @deprecated Please use `scanOptions.exclude` + * `scanOptions.exclude` overwrites this + */ + 'excludes' => [], + ], + + 'scanOptions' => [ + /** + * Configuration for default processors. Allows to pass processors configuration to swagger-php. + * + * @link https://zircote.github.io/swagger-php/reference/processors.html + */ + 'default_processors_configuration' => [ + /** Example */ + /** + * 'operationId.hash' => true, + * 'pathFilter' => [ + * 'tags' => [ + * '/pets/', + * '/store/', + * ], + * ],. + */ + ], + + /** + * analyser: defaults to \OpenApi\StaticAnalyser . + * + * @see \OpenApi\scan + */ + 'analyser' => null, + + /** + * analysis: defaults to a new \OpenApi\Analysis . + * + * @see \OpenApi\scan + */ + 'analysis' => null, + + /** + * Custom query path processors classes. + * + * @link https://github.com/zircote/swagger-php/tree/master/Examples/processors/schema-query-parameter + * @see \OpenApi\scan + */ + 'processors' => [ + // new \App\SwaggerProcessors\SchemaQueryParameter(), + ], + + /** + * pattern: string $pattern File pattern(s) to scan (default: *.php) . + * + * @see \OpenApi\scan + */ + 'pattern' => null, + + /* + * Absolute path to directories that should be excluded from scanning + * @note This option overwrites `paths.excludes` + * @see \OpenApi\scan + */ + 'exclude' => [], + + /* + * Allows to generate specs either for OpenAPI 3.0.0 or OpenAPI 3.1.0. + * By default the spec will be in version 3.0.0 + */ + 'open_api_spec_version' => env('L5_SWAGGER_OPEN_API_SPEC_VERSION', \L5Swagger\Generator::OPEN_API_DEFAULT_SPEC_VERSION), + ], + + /* + * API security definitions. Will be generated into documentation file. + */ + 'securityDefinitions' => [ + 'securitySchemes' => [ + /* + * Examples of Security schemes + */ + /* + 'api_key_security_example' => [ // Unique name of security + 'type' => 'apiKey', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'A short description for security scheme', + 'name' => 'api_key', // The name of the header or query parameter to be used. + 'in' => 'header', // The location of the API key. Valid values are "query" or "header". + ], + 'oauth2_security_example' => [ // Unique name of security + 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'A short description for oauth2 security scheme.', + 'flow' => 'implicit', // The flow used by the OAuth2 security scheme. Valid values are "implicit", "password", "application" or "accessCode". + 'authorizationUrl' => 'http://example.com/auth', // The authorization URL to be used for (implicit/accessCode) + //'tokenUrl' => 'http://example.com/auth' // The authorization URL to be used for (password/application/accessCode) + 'scopes' => [ + 'read:projects' => 'read your projects', + 'write:projects' => 'modify projects in your account', + ] + ], + */ + + /* Open API 3.0 support + 'passport' => [ // Unique name of security + 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'Laravel passport oauth2 security.', + 'in' => 'header', + 'scheme' => 'https', + 'flows' => [ + "password" => [ + "authorizationUrl" => config('app.url') . '/oauth/authorize', + "tokenUrl" => config('app.url') . '/oauth/token', + "refreshUrl" => config('app.url') . '/token/refresh', + "scopes" => [] + ], + ], + ], + */ + 'sanctum' => [ // Unique name of security + 'type' => 'apiKey', // Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'Enter token in format (Bearer