From 811ad51df552ae23a1d7afd253f7b581907c55fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Felix=20=C5=A0ulc?= Date: Mon, 18 Dec 2023 09:01:20 +0100 Subject: [PATCH] Init --- .editorconfig | 16 + .gitattributes | 10 + .github/.kodiak.toml | 10 + .github/dependabot.yml | 9 + .github/workflows/codesniffer.yml | 17 + .github/workflows/coverage.yml | 19 + .github/workflows/phpstan.yml | 18 + .github/workflows/tests.yml | 40 + .gitignore | 9 + Makefile | 82 + README.md | 77 + app/Api/Product/CreateProductController.php | 57 + app/Api/Product/CreateProductRequest.php | 10 + app/Api/Product/CreateProductResponse.php | 21 + app/Api/Product/DeleteProductController.php | 50 + app/Api/Product/DeleteProductResponse.php | 21 + app/Api/Product/GetProductController.php | 52 + app/Api/Product/GetProductResponse.php | 21 + app/Api/Product/ListProductController.php | 41 + app/Api/Product/ListProductResponse.php | 21 + app/Api/Product/UpdateProductController.php | 57 + app/Api/Product/UpdateProductRequest.php | 10 + app/Api/Product/UpdateProductResponse.php | 21 + app/Bootstrap.php | 28 + app/Domain/Routing/RouterFactory.php | 56 + app/UI/@Templates/@layout.latte | 40 + app/UI/BasePresenter.php | 10 + app/UI/Home/HomePresenter.php | 23 + app/UI/Home/Templates/default.latte | 5 + composer.json | 44 + composer.lock | 2593 +++++++++++++++++++ config/config.neon | 46 + config/local.neon | 0 config/local.neon.example | 0 phpstan.neon | 16 + ruleset.xml | 18 + tests/Cases/E2E/EntrypointTest.php | 40 + tests/IDE/apidoc.http | 6 + tests/IDE/ping.http | 6 + tests/IDE/product.http | 21 + tests/Toolkit/Tests.php | 12 + tests/bootstrap.php | 10 + var/log/.gitignore | 2 + var/tmp/.gitignore | 2 + www/.htaccess | 31 + www/index.php | 5 + 46 files changed, 3703 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .github/.kodiak.toml create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/codesniffer.yml create mode 100644 .github/workflows/coverage.yml create mode 100644 .github/workflows/phpstan.yml create mode 100644 .github/workflows/tests.yml create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 app/Api/Product/CreateProductController.php create mode 100644 app/Api/Product/CreateProductRequest.php create mode 100644 app/Api/Product/CreateProductResponse.php create mode 100644 app/Api/Product/DeleteProductController.php create mode 100644 app/Api/Product/DeleteProductResponse.php create mode 100644 app/Api/Product/GetProductController.php create mode 100644 app/Api/Product/GetProductResponse.php create mode 100644 app/Api/Product/ListProductController.php create mode 100644 app/Api/Product/ListProductResponse.php create mode 100644 app/Api/Product/UpdateProductController.php create mode 100644 app/Api/Product/UpdateProductRequest.php create mode 100644 app/Api/Product/UpdateProductResponse.php create mode 100644 app/Bootstrap.php create mode 100644 app/Domain/Routing/RouterFactory.php create mode 100644 app/UI/@Templates/@layout.latte create mode 100644 app/UI/BasePresenter.php create mode 100644 app/UI/Home/HomePresenter.php create mode 100644 app/UI/Home/Templates/default.latte create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 config/config.neon create mode 100644 config/local.neon create mode 100644 config/local.neon.example create mode 100644 phpstan.neon create mode 100644 ruleset.xml create mode 100644 tests/Cases/E2E/EntrypointTest.php create mode 100644 tests/IDE/apidoc.http create mode 100644 tests/IDE/ping.http create mode 100644 tests/IDE/product.http create mode 100644 tests/Toolkit/Tests.php create mode 100644 tests/bootstrap.php create mode 100644 var/log/.gitignore create mode 100644 var/tmp/.gitignore create mode 100644 www/.htaccess create mode 100644 www/index.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5e5b915 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig is awesome: http://EditorConfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab +indent_size = tab +tab_width = 4 + +[*.{json,yaml,yml,md}] +indent_style = space +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ee08e84 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,10 @@ +.docs export-ignore +.github export-ignore +.editorconfig export-ignore +.gitattributes export-ignore +.gitignore export-ignore +Makefile export-ignore +README.md export-ignore +phpstan.neon export-ignore +ruleset.xml export-ignore +tests export-ignore diff --git a/.github/.kodiak.toml b/.github/.kodiak.toml new file mode 100644 index 0000000..60c34b6 --- /dev/null +++ b/.github/.kodiak.toml @@ -0,0 +1,10 @@ +version = 1 + +[merge] +automerge_label = "automerge" +blacklist_title_regex = "^WIP.*" +blacklist_labels = ["WIP"] +method = "rebase" +delete_branch_on_merge = true +notify_on_conflict = true +optimistic_updates = false diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..0f0dadb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +version: 2 +updates: + - package-ecosystem: composer + directory: "/" + schedule: + interval: daily + labels: + - "dependencies" + - "automerge" diff --git a/.github/workflows/codesniffer.yml b/.github/workflows/codesniffer.yml new file mode 100644 index 0000000..6d74075 --- /dev/null +++ b/.github/workflows/codesniffer.yml @@ -0,0 +1,17 @@ +name: "Codesniffer" + +on: + pull_request: + + push: + branches: ["*"] + + schedule: + - cron: "0 8 * * 1" + +jobs: + codesniffer: + name: "Codesniffer" + uses: contributte/.github/.github/workflows/codesniffer.yml@master + with: + php: "8.2" diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..aeaf1ab --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,19 @@ +name: "Coverage" + +on: + pull_request: + workflow_dispatch: + + push: + branches: ["*"] + + schedule: + - cron: "0 8 * * 1" + +jobs: + coverage: + name: "Nette Tester" + uses: contributte/.github/.github/workflows/nette-tester-coverage-v2.yml@master + with: + php: "8.2" + make: "init coverage" diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 0000000..acf00dd --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,18 @@ +name: "Phpstan" + +on: + pull_request: + + push: + branches: ["*"] + + schedule: + - cron: "0 8 * * 1" + +jobs: + phpstan: + name: "Phpstan" + uses: contributte/.github/.github/workflows/phpstan.yml@master + with: + php: "8.2" + make: "init phpstan" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..0d29f05 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,40 @@ +name: "Phpunit" + +on: + pull_request: + + push: + branches: [ "*" ] + + schedule: + - cron: "0 8 * * 1" + +jobs: + test83: + name: "Tester" + uses: contributte/.github/.github/workflows/phpunit.yml@master + with: + php: "8.3" + make: "init tests" + + test82: + name: "Tester" + uses: contributte/.github/.github/workflows/phpunit.yml@master + with: + php: "8.2" + make: "init tests" + + test81: + name: "Tester" + uses: contributte/.github/.github/workflows/phpunit.yml@master + with: + php: "8.1" + make: "init tests" + + testlower: + name: "Tester" + uses: contributte/.github/.github/workflows/phpunit.yml@master + with: + php: "8.1" + make: "init tests" + composer: "composer update --no-interaction --no-progress --prefer-dist --prefer-stable --prefer-lowest" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b0fa45a --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# IDE +/.idea + +# Composer +/vendor +/composer.lock + +# Tests +/coverage.xml diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..63e6897 --- /dev/null +++ b/Makefile @@ -0,0 +1,82 @@ +############################################################ +# PROJECT ################################################## +############################################################ +.PHONY: project +project: install setup + +.PHONY: init +init: + cp config/local.neon.example config/local.neon + +.PHONY: install +install: + composer install + +.PHONY: setup +setup: + mkdir -p var/tmp var/log + chmod +0777 var/tmp var/log + +.PHONY: clean +clean: + find var/tmp -mindepth 1 ! -name '.gitignore' -type f,d -exec rm -rf {} + + find var/log -mindepth 1 ! -name '.gitignore' -type f,d -exec rm -rf {} + + +############################################################ +# DEVELOPMENT ############################################## +############################################################ +.PHONY: qa +qa: cs phpstan + +.PHONY: cs +cs: +ifdef GITHUB_ACTION + vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --extensions="php,phpt" --colors -nsp -q --report=checkstyle app tests | cs2pr +else + vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --extensions="php,phpt" --colors -nsp app tests +endif + +.PHONY: csf +csf: + vendor/bin/phpcbf --standard=ruleset.xml --encoding=utf-8 --extensions="php,phpt" --colors -nsp app tests + +.PHONY: phpstan +phpstan: + vendor/bin/phpstan analyse -c phpstan.neon --memory-limit=512M + +.PHONY: tests +tests: + vendor/bin/tester -s -p php --colors 1 -C tests + +.PHONY: coverage +coverage: +ifdef GITHUB_ACTION + vendor/bin/tester -s -p phpdbg --colors 1 -C --coverage coverage.xml --coverage-src app tests/Cases +else + vendor/bin/tester -s -p phpdbg --colors 1 -C --coverage coverage.html --coverage-src app tests/Cases +endif + +.PHONY: dev +dev: + NETTE_DEBUG=1 NETTE_ENV=dev php -S 0.0.0.0:8000 -t www + +.PHONY: build +build: + echo "OK" + +############################################################ +# DOCKER ################################################### +############################################################ +.PHONY: docker-up +docker-up: + docker compose up + +############################################################ +# DEPLOYMENT ############################################### +############################################################ +.PHONY: deploy +deploy: + $(MAKE) clean + $(MAKE) project + $(MAKE) build + $(MAKE) clean diff --git a/README.md b/README.md new file mode 100644 index 0000000..f8a220c --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +![](https://heatbadger.now.sh/github/readme/contributte/api-skeleton/) + +

+ + + + +

+

+ + + + + +

+ +

+Website 🚀 contributte.org | Contact 👨🏻‍💻 f3l1x.io | Twitter 🐦 @contributte +

+ +

+ +

+ +----- + +## Goal + +Main goal is to provide example of native API to [Nette](https://nette.org). + +## Demo + +https://examples.contributte.org/api-skeleton/ + +## Installation + +You will need `PHP 8.1+` and [Composer](https://getcomposer.org/). + +Create project using composer. + +```bash +composer create-project -s dev contributte/api-skeleton acme +``` + +Now you have application installed. It's time to run it. + +## Startup + +The easiest way is to use php built-in web server. + +```bash +make dev +# php -S 0.0.0.0:8000 -t www +``` + +Then visit [http://localhost:8000](http://localhost:8000) in your browser. + +**API endpoints** + +- http://localhost:8000/api/_/ping +- http://localhost:8000/api/_/apidoc +- http://localhost:8000/api/v1/product +- http://localhost:8000/api/v1/product/123456 + +## Development + +See [how to contribute](https://contributte.org/contributing.html) to this package. + +This package is currently maintaining by these authors. + + + + + +----- + +Consider to [support](https://contributte.org/partners.html) **contributte** development team. Also thank you for using this project. diff --git a/app/Api/Product/CreateProductController.php b/app/Api/Product/CreateProductController.php new file mode 100644 index 0000000..71eb260 --- /dev/null +++ b/app/Api/Product/CreateProductController.php @@ -0,0 +1,57 @@ + Expect::int()->required(), + ])->castTo(UpdateProductRequest::class); + } + + public static function describe(): Describer + { + $d = new Describer(); + $d->withPath('/api/v1/product'); + $d->withMethods([Describer::METHOD_POST]); + $d->withDescription('Create product'); + + return $d; + } + + public function __invoke(ApiRequest $request): ResponseInterface + { + try { + $entity = $this->parseBody($request, UpdateProductRequest::class); + } catch (ParsingException $e) { + return $e->getResponse(); + } + + try { + $product = [ + 'id' => $entity->id, + 'name' => 'Test', + ]; + + return UpdateProductResponse::of($product); + } catch (Throwable $e) { + return ErrorResponse::create() + ->withStatusCode(400) + ->withMessage('Cannot update detail'); + } + } + +} diff --git a/app/Api/Product/CreateProductRequest.php b/app/Api/Product/CreateProductRequest.php new file mode 100644 index 0000000..de8bae5 --- /dev/null +++ b/app/Api/Product/CreateProductRequest.php @@ -0,0 +1,10 @@ + $detail + */ + public static function of(array $detail): self + { + $self = self::create(); + $self->payload = $detail; + + return $self; + } + +} diff --git a/app/Api/Product/DeleteProductController.php b/app/Api/Product/DeleteProductController.php new file mode 100644 index 0000000..1db8bb6 --- /dev/null +++ b/app/Api/Product/DeleteProductController.php @@ -0,0 +1,50 @@ +withPath('/api/v1/product/'); + $d->withMethods([Describer::METHOD_DELETE]); + $d->withDescription('Delete product'); + + return $d; + } + + public function __invoke(ApiRequest $request): ResponseInterface + { + $id = $request->getParameter('id'); + + // Validate parameters + if ($id === null) { + return ErrorResponse::create() + ->withStatusCode(400) + ->withMessage('Invalid ID'); + } + + try { + $product = [ + 'id' => 1, + 'name' => 'Test', + ]; + + return GetProductResponse::of($product); + } catch (Throwable $e) { + return ErrorResponse::create() + ->withStatusCode(400) + ->withMessage('Cannot load detail'); + } + } + +} diff --git a/app/Api/Product/DeleteProductResponse.php b/app/Api/Product/DeleteProductResponse.php new file mode 100644 index 0000000..f7c58ac --- /dev/null +++ b/app/Api/Product/DeleteProductResponse.php @@ -0,0 +1,21 @@ + $detail + */ + public static function of(array $detail): self + { + $self = self::create(); + $self->payload = $detail; + + return $self; + } + +} diff --git a/app/Api/Product/GetProductController.php b/app/Api/Product/GetProductController.php new file mode 100644 index 0000000..b2997c8 --- /dev/null +++ b/app/Api/Product/GetProductController.php @@ -0,0 +1,52 @@ +withPath('/api/v1/product/'); + $d->withMethods([Describer::METHOD_GET]); + $d->withDescription('Get product'); + + return $d; + } + + public function __invoke(ApiRequest $request): ResponseInterface + { + $id = $request->getParameter('uuid'); + + // Validate parameters + if ($id === null) { + return ErrorResponse::create() + ->withStatusCode(400) + ->withMessage('Invalid ID'); + } + + try { + // Load data from DB + $product = [ + 'id' => 1, + 'name' => 'Test', + ]; + } catch (Throwable $e) { // @phpstan-ignore-line + return ErrorResponse::create() + ->withStatusCode(400) + ->withMessage('Cannot load detail'); + } + + // Send response + return GetProductResponse::of($product); + } + +} diff --git a/app/Api/Product/GetProductResponse.php b/app/Api/Product/GetProductResponse.php new file mode 100644 index 0000000..846fe33 --- /dev/null +++ b/app/Api/Product/GetProductResponse.php @@ -0,0 +1,21 @@ + $detail + */ + public static function of(array $detail): self + { + $self = self::create(); + $self->payload = $detail; + + return $self; + } + +} diff --git a/app/Api/Product/ListProductController.php b/app/Api/Product/ListProductController.php new file mode 100644 index 0000000..b59ba1a --- /dev/null +++ b/app/Api/Product/ListProductController.php @@ -0,0 +1,41 @@ +withPath('/api/v1/product'); + $d->withMethods([Describer::METHOD_GET]); + $d->withDescription('List product'); + + return $d; + } + + public function __invoke(ApiRequest $request): ResponseInterface + { + try { + $product = [ + 'id' => 1, + 'name' => 'Test', + ]; + + return GetProductResponse::of($product); + } catch (Throwable $e) { + return ErrorResponse::create() + ->withStatusCode(400) + ->withMessage('Cannot load detail'); + } + } + +} diff --git a/app/Api/Product/ListProductResponse.php b/app/Api/Product/ListProductResponse.php new file mode 100644 index 0000000..90e5453 --- /dev/null +++ b/app/Api/Product/ListProductResponse.php @@ -0,0 +1,21 @@ + $detail + */ + public static function of(array $detail): self + { + $self = self::create(); + $self->payload = $detail; + + return $self; + } + +} diff --git a/app/Api/Product/UpdateProductController.php b/app/Api/Product/UpdateProductController.php new file mode 100644 index 0000000..a9211f4 --- /dev/null +++ b/app/Api/Product/UpdateProductController.php @@ -0,0 +1,57 @@ +withPath('/api/v1/product/{uuid}'); + $d->withMethods([Describer::METHOD_PUT]); + $d->withDescription('Update product'); + + return $d; + } + + public static function schema(): Schema + { + return Expect::structure([ + 'id' => Expect::int()->required(), + ])->castTo(UpdateProductRequest::class); + } + + public function __invoke(ApiRequest $request): ResponseInterface + { + try { + $entity = $this->parseBody($request, UpdateProductRequest::class); + } catch (ParsingException $e) { + return $e->getResponse(); + } + + try { + $product = [ + 'id' => $entity->id, + 'name' => 'Test', + ]; + + return UpdateProductResponse::of($product); + } catch (Throwable $e) { + return ErrorResponse::create() + ->withStatusCode(400) + ->withMessage('Cannot update detail'); + } + } + +} diff --git a/app/Api/Product/UpdateProductRequest.php b/app/Api/Product/UpdateProductRequest.php new file mode 100644 index 0000000..0ab3c72 --- /dev/null +++ b/app/Api/Product/UpdateProductRequest.php @@ -0,0 +1,10 @@ + $detail + */ + public static function of(array $detail): self + { + $self = self::create(); + $self->payload = $detail; + + return $self; + } + +} diff --git a/app/Bootstrap.php b/app/Bootstrap.php new file mode 100644 index 0000000..341631f --- /dev/null +++ b/app/Bootstrap.php @@ -0,0 +1,28 @@ +use(NellaPreset::create(__DIR__)) + ->boot(); + } + + public static function run(): void + { + self::boot() + ->createContainer() + ->getByType(Application::class) + ->run(); + } + +} diff --git a/app/Domain/Routing/RouterFactory.php b/app/Domain/Routing/RouterFactory.php new file mode 100644 index 0000000..5479fce --- /dev/null +++ b/app/Domain/Routing/RouterFactory.php @@ -0,0 +1,56 @@ +withPath('api'); + $api->add('GET', '_/apidoc', OpenapiController::class)->tag(['public']); + $api->add('GET', '_/ping', PingController::class)->tag(['public']); + + // /api/v1 + $v1 = (new ApiRouter($api))->withPath('v1'); + + // /api/v1/product + $v1->add('GET', 'product', ListProductController::class); + $v1->add('GET', 'product/', GetProductController::class); + $v1->add('POST', 'product', CreateProductController::class); + $v1->add('PUT', 'product/', UpdateProductController::class); + $v1->add('DELETE', 'product/', DeleteProductController::class); + + // /api/* + $api->add('GET', '', PingController::class); + } + + public static function createGui(RouteList $router): void + { + $router[] = new Route('/[/]', 'Home:default'); + } + +} diff --git a/app/UI/@Templates/@layout.latte b/app/UI/@Templates/@layout.latte new file mode 100644 index 0000000..a404847 --- /dev/null +++ b/app/UI/@Templates/@layout.latte @@ -0,0 +1,40 @@ + + + + + + + {block #title|striptags}API Skeleton{/} + + + + + +
+
+
+

+ Contributte / API Skeleton +

+
+ +
+
+ {$flash->message} +
+
+ +
+ {include #content} +
+ +
+ © {=date(Y)} by @f3l1x +
+
+
+ + + + + diff --git a/app/UI/BasePresenter.php b/app/UI/BasePresenter.php new file mode 100644 index 0000000..ae2bbf7 --- /dev/null +++ b/app/UI/BasePresenter.php @@ -0,0 +1,10 @@ + + /api/v1/product + diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..0cac482 --- /dev/null +++ b/composer.json @@ -0,0 +1,44 @@ +{ + "name": "contributte/api-skeleton", + "description": "API project skeleton based on Nette Framework (@nette) and Contributte (@contributte) libraries by @f3l1x", + "keywords": [ + "nette", + "skeleton", + "project", + "api", + "rest", + "json" + ], + "license": "MIT", + "type": "project", + "require": { + "php": ">=8.1", + "contributte/nella": "^0.2", + "contributte/api": "^0.5" + }, + "require-dev": { + "contributte/qa": "^0.3", + "contributte/dev": "^0.4", + "contributte/tester": "^0.3", + "contributte/phpstan": "^0.1" + }, + "autoload": { + "psr-4": { + "App\\": "app" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests" + } + }, + "prefer-stable": true, + "minimum-stability": "dev", + "config": { + "sort-packages": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "php-http/discovery": true + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..e55b7fe --- /dev/null +++ b/composer.lock @@ -0,0 +1,2593 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "9a851cf9400fc503f21829a350aca1bd", + "packages": [ + { + "name": "contributte/api", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/contributte/api.git", + "reference": "8350ceb66deb6d5d3a3164e4226e58c766458473" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/api/zipball/8350ceb66deb6d5d3a3164e4226e58c766458473", + "reference": "8350ceb66deb6d5d3a3164e4226e58c766458473", + "shasum": "" + }, + "require": { + "nette/application": "^3.1.4", + "nette/di": "^3.1.8", + "nette/http": "^3.2.3", + "nette/utils": "^4.0.3", + "php": ">=8.1" + }, + "conflict": { + "nette/neon": "<3.4.0" + }, + "require-dev": { + "contributte/phpstan": "^0.1", + "contributte/qa": "^0.4", + "contributte/tester": "^0.3", + "mockery/mockery": "^1.5.0", + "tracy/tracy": "^2.10.5" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Contributte\\Api\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Powerful, documented, validated, built-in API to Nette Framework (@nette)", + "homepage": "https://github.com/contributte/api", + "keywords": [ + "api", + "json", + "nette", + "rest" + ], + "support": { + "issues": "https://github.com/contributte/api/issues", + "source": "https://github.com/contributte/api/tree/v0.4.0" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2023-12-17T18:12:23+00:00" + }, + { + "name": "contributte/application", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/contributte/application.git", + "reference": "8b7c16cd70c8d8af24d5c788c9fe4d6273f08158" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/application/zipball/8b7c16cd70c8d8af24d5c788c9fe4d6273f08158", + "reference": "8b7c16cd70c8d8af24d5c788c9fe4d6273f08158", + "shasum": "" + }, + "require": { + "nette/application": "^3.1.11 || ^4.0.0", + "php": ">=8.1" + }, + "require-dev": { + "contributte/phpstan": "^0.1.0", + "contributte/qa": "^0.4.0", + "contributte/tester": "^0.3.0", + "nette/http": "^4.0.0", + "psr/http-message": "~1.0.1", + "tracy/tracy": "~2.9.1" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Contributte\\Application\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Extra contrib to nette/application", + "homepage": "https://github.com/contributte/application", + "keywords": [ + "application", + "component", + "control", + "nette", + "presenter" + ], + "support": { + "issues": "https://github.com/contributte/application/issues", + "source": "https://github.com/contributte/application/tree/master" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2023-09-28T13:43:24+00:00" + }, + { + "name": "contributte/bootstrap", + "version": "v0.6.0", + "source": { + "type": "git", + "url": "https://github.com/contributte/bootstrap.git", + "reference": "6f6d0e7aaf63c62b2f38a1fdd29ee316ccadd2d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/bootstrap/zipball/6f6d0e7aaf63c62b2f38a1fdd29ee316ccadd2d1", + "reference": "6f6d0e7aaf63c62b2f38a1fdd29ee316ccadd2d1", + "shasum": "" + }, + "require": { + "nette/bootstrap": "^3.2.0", + "nette/utils": "^3.2.9 || ^4.0.0", + "php": ">=7.4" + }, + "require-dev": { + "ninjify/nunjuck": "^0.4", + "ninjify/qa": "^0.12", + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-nette": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.7-dev" + } + }, + "autoload": { + "psr-4": { + "Contributte\\Bootstrap\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Extra contrib to nette/boostrap", + "homepage": "https://github.com/contributte/bootstrap", + "keywords": [ + "application", + "bootstrap", + "docker", + "nette" + ], + "support": { + "issues": "https://github.com/contributte/bootstrap/issues", + "source": "https://github.com/contributte/bootstrap/tree/v0.6.0" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2023-04-24T20:25:44+00:00" + }, + { + "name": "contributte/di", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/contributte/di.git", + "reference": "49d6b93d46f57be319b1e811cd983bfed0c90979" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/di/zipball/49d6b93d46f57be319b1e811cd983bfed0c90979", + "reference": "49d6b93d46f57be319b1e811cd983bfed0c90979", + "shasum": "" + }, + "require": { + "nette/di": "^3.1.0", + "nette/utils": "^3.2.8 || ^4.0", + "php": ">=7.2" + }, + "conflict": { + "nette/schema": "<1.1.0" + }, + "require-dev": { + "nette/bootstrap": "^3.1.4", + "nette/robot-loader": "^3.4.2 || ^4.0", + "ninjify/nunjuck": "^0.4", + "ninjify/qa": "^0.13", + "phpstan/phpstan": "^1.9.11", + "phpstan/phpstan-deprecation-rules": "^1.1.1", + "phpstan/phpstan-nette": "^1.2.0", + "phpstan/phpstan-strict-rules": "^1.4.5" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Contributte\\DI\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Extra contrib to nette/di", + "homepage": "https://github.com/contributte/di", + "keywords": [ + "dependency", + "inject", + "nette" + ], + "support": { + "issues": "https://github.com/contributte/di/issues", + "source": "https://github.com/contributte/di/tree/v0.5.6" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2023-09-05T08:23:55+00:00" + }, + { + "name": "contributte/forms", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/contributte/forms.git", + "reference": "c7ac26b456ff2958ea207c43be6515ad1154dcea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/forms/zipball/c7ac26b456ff2958ea207c43be6515ad1154dcea", + "reference": "c7ac26b456ff2958ea207c43be6515ad1154dcea", + "shasum": "" + }, + "require": { + "nette/forms": "^3.0.0", + "php": ">=7.2" + }, + "conflict": { + "nette/di": "<3.0.0" + }, + "require-dev": { + "nette/application": "^3.0.0", + "nette/di": "^3.1.0", + "ninjify/nunjuck": "^0.4", + "ninjify/qa": "^0.12", + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-nette": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1" + }, + "suggest": { + "nette/di": "to use FormFactoryExtension[CompilerExtension]" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Contributte\\Forms\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Extra contrib to nette/forms", + "homepage": "https://github.com/contributte/forms", + "keywords": [ + "Forms", + "checkbox", + "inputs", + "nette", + "renderers", + "rules", + "validation" + ], + "support": { + "issues": "https://github.com/contributte/forms/issues", + "source": "https://github.com/contributte/forms/tree/v0.5.1" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2022-11-13T17:22:04+00:00" + }, + { + "name": "contributte/latte", + "version": "v0.6.0", + "source": { + "type": "git", + "url": "https://github.com/contributte/latte.git", + "reference": "f558925e5b9e29e669f242fdfd3dcb520652b9c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/latte/zipball/f558925e5b9e29e669f242fdfd3dcb520652b9c3", + "reference": "f558925e5b9e29e669f242fdfd3dcb520652b9c3", + "shasum": "" + }, + "require": { + "latte/latte": "^3.0.12", + "php": ">=8.1" + }, + "require-dev": { + "contributte/phpstan": "^0.1", + "contributte/qa": "^0.4", + "contributte/tester": "^0.4", + "nette/application": "^3.1.14", + "nette/di": "^3.0.17" + }, + "suggest": { + "nette/di": "to use VersionExtension[CompilerExtension]" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Contributte\\Latte\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Extra contrib to nette/latte", + "homepage": "https://github.com/contributte/latte", + "keywords": [ + "extra", + "latte", + "nette" + ], + "support": { + "issues": "https://github.com/contributte/latte/issues", + "source": "https://github.com/contributte/latte/tree/v0.6.0" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2023-12-12T19:43:05+00:00" + }, + { + "name": "contributte/nella", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/contributte/nella.git", + "reference": "1f35cc864ba504eb524d51ff233c0f89be876d6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/nella/zipball/1f35cc864ba504eb524d51ff233c0f89be876d6b", + "reference": "1f35cc864ba504eb524d51ff233c0f89be876d6b", + "shasum": "" + }, + "require": { + "contributte/application": "^0.6.0", + "contributte/bootstrap": "^0.6.0", + "contributte/di": "^0.6.0", + "contributte/forms": "^0.6.0", + "contributte/latte": "^0.6.0", + "contributte/tracy": "^0.6.0", + "contributte/utils": "^0.6.0", + "php": ">=8.1" + }, + "require-dev": { + "contributte/phpstan": "^0.1", + "contributte/qa": "^0.4", + "contributte/tester": "^0.3", + "mockery/mockery": "^1.5.0" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Contributte\\Nella\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Opinionated pre-configured kernel based on Nette (@nette). Suitable for all kind apps.", + "homepage": "https://github.com/contributte/nella", + "keywords": [ + "kernel", + "nella", + "nette", + "stack" + ], + "support": { + "issues": "https://github.com/contributte/nella/issues", + "source": "https://github.com/contributte/nella/tree/master" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2023-12-18T07:52:12+00:00" + }, + { + "name": "contributte/tracy", + "version": "v0.6.0", + "source": { + "type": "git", + "url": "https://github.com/contributte/tracy.git", + "reference": "36b64184b8042fc59eff49a2a2d32c56c24298fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/tracy/zipball/36b64184b8042fc59eff49a2a2d32c56c24298fe", + "reference": "36b64184b8042fc59eff49a2a2d32c56c24298fe", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "tracy/tracy": "^2.9.0" + }, + "conflict": { + "nette/di": "<3.1.0" + }, + "require-dev": { + "contributte/phpstan": "^0.1", + "contributte/qa": "^0.4", + "contributte/tester": "^0.3", + "mockery/mockery": "^1.5.0", + "nette/di": "^3.1.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Contributte\\Tracy\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Nette Tracy extensions for easy-developing", + "homepage": "https://github.com/contributte/tracy", + "keywords": [ + "bluescreen", + "develop", + "navigation", + "nette", + "profile", + "tracy" + ], + "support": { + "issues": "https://github.com/contributte/tracy/issues", + "source": "https://github.com/contributte/tracy/tree/v0.6.0" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2023-07-31T15:00:21+00:00" + }, + { + "name": "contributte/utils", + "version": "v0.6.0", + "source": { + "type": "git", + "url": "https://github.com/contributte/utils.git", + "reference": "f9796645d3cc2b0fa75ee5de0e35d24421feb35e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/utils/zipball/f9796645d3cc2b0fa75ee5de0e35d24421feb35e", + "reference": "f9796645d3cc2b0fa75ee5de0e35d24421feb35e", + "shasum": "" + }, + "require": { + "nette/utils": "^3.2.9 || ^4.0.0", + "php": ">=8.0" + }, + "conflict": { + "nette/di": "<3.0.0" + }, + "require-dev": { + "nette/di": "^3.1.0", + "ninjify/nunjuck": "^0.4.0", + "ninjify/qa": "^0.12.0", + "phpstan/phpstan": "^1.9.0", + "phpstan/phpstan-deprecation-rules": "^1.1.0", + "phpstan/phpstan-nette": "^1.2.0", + "phpstan/phpstan-strict-rules": "^1.4.0" + }, + "suggest": { + "nette/di": "to use DateTimeExtension[CompilerExtension]" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Contributte\\Utils\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Extra contrib to nette/utils", + "homepage": "https://github.com/contributte/utils", + "keywords": [ + "datetime", + "filesystem", + "nette", + "strings", + "utils" + ], + "support": { + "issues": "https://github.com/contributte/utils/issues", + "source": "https://github.com/contributte/utils/tree/v0.6.0" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2023-04-25T12:54:31+00:00" + }, + { + "name": "latte/latte", + "version": "v3.0.12", + "source": { + "type": "git", + "url": "https://github.com/nette/latte.git", + "reference": "af6fc60e7a28cbc1717b8185ef04d36fd69f8711" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/latte/zipball/af6fc60e7a28cbc1717b8185ef04d36fd69f8711", + "reference": "af6fc60e7a28cbc1717b8185ef04d36fd69f8711", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "php": "8.0 - 8.3" + }, + "conflict": { + "nette/application": "<3.1.7", + "nette/caching": "<3.1.4" + }, + "require-dev": { + "nette/php-generator": "^3.6 || ^4.0", + "nette/tester": "^2.0", + "nette/utils": "^3.0", + "phpstan/phpstan": "^1", + "tracy/tracy": "^2.3" + }, + "suggest": { + "ext-fileinfo": "to use filter |datastream", + "ext-iconv": "to use filters |reverse, |substring", + "ext-mbstring": "to use filters like lower, upper, capitalize, ...", + "nette/php-generator": "to use tag {templatePrint}", + "nette/utils": "to use filter |webalize" + }, + "bin": [ + "bin/latte-lint" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "☕ Latte: the intuitive and fast template engine for those who want the most secure PHP sites. Introduces context-sensitive escaping.", + "homepage": "https://latte.nette.org", + "keywords": [ + "context-sensitive", + "engine", + "escaping", + "html", + "nette", + "security", + "template", + "twig" + ], + "support": { + "issues": "https://github.com/nette/latte/issues", + "source": "https://github.com/nette/latte/tree/v3.0.12" + }, + "time": "2023-11-13T11:31:09+00:00" + }, + { + "name": "nette/application", + "version": "v3.1.14", + "source": { + "type": "git", + "url": "https://github.com/nette/application.git", + "reference": "0729ede7e66fad642046a3eb670d368845272573" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/application/zipball/0729ede7e66fad642046a3eb670d368845272573", + "reference": "0729ede7e66fad642046a3eb670d368845272573", + "shasum": "" + }, + "require": { + "nette/component-model": "^3.0", + "nette/http": "^3.0.2", + "nette/routing": "^3.0.5", + "nette/utils": "^3.2.1 || ~4.0.0", + "php": ">=7.2" + }, + "conflict": { + "latte/latte": "<2.7.1 || >=3.0.0 <3.0.8 || >=3.1", + "nette/caching": "<3.1", + "nette/di": "<3.0.7", + "nette/forms": "<3.0", + "nette/schema": "<1.2", + "tracy/tracy": "<2.5" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "latte/latte": "^2.10.2 || ^3.0.3", + "mockery/mockery": "^1.0", + "nette/di": "^v3.0", + "nette/forms": "^3.0", + "nette/robot-loader": "^3.2", + "nette/security": "^3.0", + "nette/tester": "^2.3.1", + "phpstan/phpstan-nette": "^0.12", + "tracy/tracy": "^2.6" + }, + "suggest": { + "latte/latte": "Allows using Latte in templates", + "nette/forms": "Allows to use Nette\\Application\\UI\\Form" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🏆 Nette Application: a full-stack component-based MVC kernel for PHP that helps you write powerful and modern web applications. Write less, have cleaner code and your work will bring you joy.", + "homepage": "https://nette.org", + "keywords": [ + "Forms", + "component-based", + "control", + "framework", + "mvc", + "mvp", + "nette", + "presenter", + "routing", + "seo" + ], + "support": { + "issues": "https://github.com/nette/application/issues", + "source": "https://github.com/nette/application/tree/v3.1.14" + }, + "time": "2023-10-09T02:45:43+00:00" + }, + { + "name": "nette/bootstrap", + "version": "v3.2.1", + "source": { + "type": "git", + "url": "https://github.com/nette/bootstrap.git", + "reference": "eeb1c9dc9f1391bd03aeeb6cc0e456ec9b247f5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/bootstrap/zipball/eeb1c9dc9f1391bd03aeeb6cc0e456ec9b247f5c", + "reference": "eeb1c9dc9f1391bd03aeeb6cc0e456ec9b247f5c", + "shasum": "" + }, + "require": { + "nette/di": "^3.1", + "nette/utils": "^3.2.1 || ^4.0", + "php": "8.0 - 8.3" + }, + "conflict": { + "tracy/tracy": "<2.6" + }, + "require-dev": { + "latte/latte": "^2.8 || ^3.0", + "nette/application": "^3.1", + "nette/caching": "^3.0", + "nette/database": "^3.0", + "nette/forms": "^3.0", + "nette/http": "^3.0", + "nette/mail": "^3.0 || ^4.0", + "nette/robot-loader": "^3.0 || ^4.0", + "nette/safe-stream": "^2.2", + "nette/security": "^3.0", + "nette/tester": "^2.4", + "phpstan/phpstan-nette": "^1.0", + "tracy/tracy": "^2.9" + }, + "suggest": { + "nette/robot-loader": "to use Configurator::createRobotLoader()", + "tracy/tracy": "to use Configurator::enableTracy()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🅱 Nette Bootstrap: the simple way to configure and bootstrap your Nette application.", + "homepage": "https://nette.org", + "keywords": [ + "bootstrapping", + "configurator", + "nette" + ], + "support": { + "issues": "https://github.com/nette/bootstrap/issues", + "source": "https://github.com/nette/bootstrap/tree/v3.2.1" + }, + "time": "2023-09-23T01:12:54+00:00" + }, + { + "name": "nette/component-model", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/nette/component-model.git", + "reference": "9d97c0e1916bbf8e306283ab187834501fd4b1f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/component-model/zipball/9d97c0e1916bbf8e306283ab187834501fd4b1f5", + "reference": "9d97c0e1916bbf8e306283ab187834501fd4b1f5", + "shasum": "" + }, + "require": { + "nette/utils": "^2.5 || ^3.0 || ~4.0.0", + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "^2.0", + "phpstan/phpstan": "^0.12", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "⚛ Nette Component Model", + "homepage": "https://nette.org", + "keywords": [ + "components", + "nette" + ], + "support": { + "issues": "https://github.com/nette/component-model/issues", + "source": "https://github.com/nette/component-model/tree/v3.0.3" + }, + "time": "2023-01-09T20:16:05+00:00" + }, + { + "name": "nette/di", + "version": "v3.1.8", + "source": { + "type": "git", + "url": "https://github.com/nette/di.git", + "reference": "adf475076dae08109dd0d57b1a48668d1d1bedf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/di/zipball/adf475076dae08109dd0d57b1a48668d1d1bedf0", + "reference": "adf475076dae08109dd0d57b1a48668d1d1bedf0", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "nette/neon": "^3.3 || ^4.0", + "nette/php-generator": "^3.5.4 || ^4.0", + "nette/robot-loader": "^3.2 || ~4.0.0", + "nette/schema": "^1.2.5", + "nette/utils": "^3.2.5 || ~4.0.0", + "php": "7.2 - 8.3" + }, + "require-dev": { + "nette/tester": "^2.4", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "💎 Nette Dependency Injection Container: Flexible, compiled and full-featured DIC with perfectly usable autowiring and support for all new PHP features.", + "homepage": "https://nette.org", + "keywords": [ + "compiled", + "di", + "dic", + "factory", + "ioc", + "nette", + "static" + ], + "support": { + "issues": "https://github.com/nette/di/issues", + "source": "https://github.com/nette/di/tree/v3.1.8" + }, + "time": "2023-11-03T00:12:52+00:00" + }, + { + "name": "nette/forms", + "version": "v3.1.14", + "source": { + "type": "git", + "url": "https://github.com/nette/forms.git", + "reference": "888aba2947e0878303b001827abe25ca86530a75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/forms/zipball/888aba2947e0878303b001827abe25ca86530a75", + "reference": "888aba2947e0878303b001827abe25ca86530a75", + "shasum": "" + }, + "require": { + "nette/component-model": "^3.0", + "nette/http": "^3.1", + "nette/utils": "^3.2.5 || ~4.0.0", + "php": "7.2 - 8.3" + }, + "conflict": { + "latte/latte": ">=3.1" + }, + "require-dev": { + "latte/latte": "^2.10.2 || ^3.0.8", + "nette/application": "^3.0", + "nette/di": "^3.0", + "nette/tester": "^2.4", + "phpstan/phpstan-nette": "^1", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-intl": "to use date/time controls" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📝 Nette Forms: generating, validating and processing secure forms in PHP. Handy API, fully customizable, server & client side validation and mature design.", + "homepage": "https://nette.org", + "keywords": [ + "Forms", + "bootstrap", + "csrf", + "javascript", + "nette", + "validation" + ], + "support": { + "issues": "https://github.com/nette/forms/issues", + "source": "https://github.com/nette/forms/tree/v3.1.14" + }, + "time": "2023-11-02T02:12:12+00:00" + }, + { + "name": "nette/http", + "version": "v3.2.3", + "source": { + "type": "git", + "url": "https://github.com/nette/http.git", + "reference": "54d79711ff3a8dfd86201e3bdbdd6972177ea20b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/http/zipball/54d79711ff3a8dfd86201e3bdbdd6972177ea20b", + "reference": "54d79711ff3a8dfd86201e3bdbdd6972177ea20b", + "shasum": "" + }, + "require": { + "nette/utils": "^3.2.1 || ~4.0.0", + "php": "7.2 - 8.3" + }, + "conflict": { + "nette/di": "<3.0.3", + "nette/schema": "<1.2" + }, + "require-dev": { + "nette/di": "^3.0", + "nette/security": "^3.0", + "nette/tester": "^2.4", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.8" + }, + "suggest": { + "ext-fileinfo": "to detect type of uploaded files" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🌐 Nette Http: abstraction for HTTP request, response and session. Provides careful data sanitization and utility for URL and cookies manipulation.", + "homepage": "https://nette.org", + "keywords": [ + "cookies", + "http", + "nette", + "proxy", + "request", + "response", + "security", + "session", + "url" + ], + "support": { + "issues": "https://github.com/nette/http/issues", + "source": "https://github.com/nette/http/tree/v3.2.3" + }, + "time": "2023-11-02T02:43:54+00:00" + }, + { + "name": "nette/neon", + "version": "v3.4.1", + "source": { + "type": "git", + "url": "https://github.com/nette/neon.git", + "reference": "457bfbf0560f600b30d9df4233af382a478bb44d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/neon/zipball/457bfbf0560f600b30d9df4233af382a478bb44d", + "reference": "457bfbf0560f600b30d9df4233af382a478bb44d", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "8.0 - 8.3" + }, + "require-dev": { + "nette/tester": "^2.4", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.7" + }, + "bin": [ + "bin/neon-lint" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🍸 Nette NEON: encodes and decodes NEON file format.", + "homepage": "https://ne-on.org", + "keywords": [ + "export", + "import", + "neon", + "nette", + "yaml" + ], + "support": { + "issues": "https://github.com/nette/neon/issues", + "source": "https://github.com/nette/neon/tree/v3.4.1" + }, + "time": "2023-09-27T08:59:11+00:00" + }, + { + "name": "nette/php-generator", + "version": "v4.1.2", + "source": { + "type": "git", + "url": "https://github.com/nette/php-generator.git", + "reference": "abc0e79b2d02d4b8aba5933765b90df3f610c143" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/php-generator/zipball/abc0e79b2d02d4b8aba5933765b90df3f610c143", + "reference": "abc0e79b2d02d4b8aba5933765b90df3f610c143", + "shasum": "" + }, + "require": { + "nette/utils": "^3.2.9 || ^4.0", + "php": "8.0 - 8.3" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.4", + "nikic/php-parser": "^4.15", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.8" + }, + "suggest": { + "nikic/php-parser": "to use ClassType::from(withBodies: true) & ClassType::fromCode()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.3 features.", + "homepage": "https://nette.org", + "keywords": [ + "code", + "nette", + "php", + "scaffolding" + ], + "support": { + "issues": "https://github.com/nette/php-generator/issues", + "source": "https://github.com/nette/php-generator/tree/v4.1.2" + }, + "time": "2023-10-29T22:57:32+00:00" + }, + { + "name": "nette/robot-loader", + "version": "v4.0.1", + "source": { + "type": "git", + "url": "https://github.com/nette/robot-loader.git", + "reference": "3a947efaff55d48e8cdba5b338bf3a4b708a624a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/robot-loader/zipball/3a947efaff55d48e8cdba5b338bf3a4b708a624a", + "reference": "3a947efaff55d48e8cdba5b338bf3a4b708a624a", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "nette/utils": "^4.0", + "php": "8.0 - 8.3" + }, + "require-dev": { + "nette/tester": "^2.4", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🍀 Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.", + "homepage": "https://nette.org", + "keywords": [ + "autoload", + "class", + "interface", + "nette", + "trait" + ], + "support": { + "issues": "https://github.com/nette/robot-loader/issues", + "source": "https://github.com/nette/robot-loader/tree/v4.0.1" + }, + "time": "2023-09-26T18:09:36+00:00" + }, + { + "name": "nette/routing", + "version": "v3.0.5", + "source": { + "type": "git", + "url": "https://github.com/nette/routing.git", + "reference": "ff709ff9ed38a14c4fe3472534526593a8461ff5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/routing/zipball/ff709ff9ed38a14c4fe3472534526593a8461ff5", + "reference": "ff709ff9ed38a14c4fe3472534526593a8461ff5", + "shasum": "" + }, + "require": { + "nette/http": "^3.0 || ~4.0.0", + "nette/utils": "^3.0 || ~4.0.0", + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "^2.0", + "phpstan/phpstan": "^1", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "Nette Routing: two-ways URL conversion", + "homepage": "https://nette.org", + "keywords": [ + "nette" + ], + "support": { + "issues": "https://github.com/nette/routing/issues", + "source": "https://github.com/nette/routing/tree/v3.0.5" + }, + "time": "2023-10-08T21:37:46+00:00" + }, + { + "name": "nette/schema", + "version": "v1.2.5", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/0462f0166e823aad657c9224d0f849ecac1ba10a", + "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a", + "shasum": "" + }, + "require": { + "nette/utils": "^2.5.7 || ^3.1.5 || ^4.0", + "php": "7.1 - 8.3" + }, + "require-dev": { + "nette/tester": "^2.3 || ^2.4", + "phpstan/phpstan-nette": "^1.0", + "tracy/tracy": "^2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.2.5" + }, + "time": "2023-10-05T20:37:59+00:00" + }, + { + "name": "nette/utils", + "version": "v4.0.3", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "a9d127dd6a203ce6d255b2e2db49759f7506e015" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/a9d127dd6a203ce6d255b2e2db49759f7506e015", + "reference": "a9d127dd6a203ce6d255b2e2db49759f7506e015", + "shasum": "" + }, + "require": { + "php": ">=8.0 <8.4" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.5", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.0.3" + }, + "time": "2023-10-29T21:02:13+00:00" + }, + { + "name": "tracy/tracy", + "version": "v2.10.5", + "source": { + "type": "git", + "url": "https://github.com/nette/tracy.git", + "reference": "86bdba4aa0f707d3f125933931d3df6e5c7aad79" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/tracy/zipball/86bdba4aa0f707d3f125933931d3df6e5c7aad79", + "reference": "86bdba4aa0f707d3f125933931d3df6e5c7aad79", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-session": "*", + "php": ">=8.0 <8.4" + }, + "conflict": { + "nette/di": "<3.0" + }, + "require-dev": { + "latte/latte": "^2.5", + "nette/di": "^3.0", + "nette/http": "^3.0", + "nette/mail": "^3.0", + "nette/tester": "^2.2", + "nette/utils": "^3.0", + "phpstan/phpstan": "^1.0", + "psr/log": "^1.0 || ^2.0 || ^3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.10-dev" + } + }, + "autoload": { + "files": [ + "src/Tracy/functions.php" + ], + "classmap": [ + "src" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "😎 Tracy: the addictive tool to ease debugging PHP code for cool developers. Friendly design, logging, profiler, advanced features like debugging AJAX calls or CLI support. You will love it.", + "homepage": "https://tracy.nette.org", + "keywords": [ + "Xdebug", + "debug", + "debugger", + "nette", + "profiler" + ], + "support": { + "issues": "https://github.com/nette/tracy/issues", + "source": "https://github.com/nette/tracy/tree/v2.10.5" + }, + "time": "2023-10-16T21:54:18+00:00" + } + ], + "packages-dev": [ + { + "name": "contributte/dev", + "version": "v0.4", + "source": { + "type": "git", + "url": "https://github.com/contributte/dev.git", + "reference": "ad662e623a4d3d7e98b4d647eb4a6681f7c0ae1b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/dev/zipball/ad662e623a4d3d7e98b4d647eb4a6681f7c0ae1b", + "reference": "ad662e623a4d3d7e98b4d647eb4a6681f7c0ae1b", + "shasum": "" + }, + "require": { + "contributte/tracy": "^0.6.0", + "contributte/utils": "^0.6.0", + "php": ">=8.1" + }, + "require-dev": { + "contributte/phpstan": "^0.1.0", + "contributte/phpunit": "^0.1.0", + "contributte/qa": "^0.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.5.x-dev" + } + }, + "autoload": { + "files": [ + "src/shortcuts.php" + ], + "psr-4": { + "Contributte\\Dev\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Sulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Tools for development with Nette and Tracy", + "homepage": "https://github.com/contributte/dev", + "keywords": [ + "debugger", + "development", + "functions", + "nette", + "shortcuts" + ], + "support": { + "issues": "https://github.com/contributte/dev/issues", + "source": "https://github.com/contributte/dev/tree/v0.4" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2023-06-09T19:56:08+00:00" + }, + { + "name": "contributte/phpstan", + "version": "v0.1.0", + "source": { + "type": "git", + "url": "https://github.com/contributte/phpstan.git", + "reference": "12731b3619c55d31bdbae73f814d6b7ee976c1e3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/phpstan/zipball/12731b3619c55d31bdbae73f814d6b7ee976c1e3", + "reference": "12731b3619c55d31bdbae73f814d6b7ee976c1e3", + "shasum": "" + }, + "require": { + "php": ">=8.0", + "phpstan/phpstan": "^1.10.15", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-nette": "^1.2.9", + "phpstan/phpstan-strict-rules": "^1.5.1" + }, + "require-dev": { + "contributte/qa": "^0.4", + "contributte/tester": "^0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Contributte\\Phpstan\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Opinionated set of phpstan extensions & rules for all fans.", + "homepage": "https://github.com/contributte/phpstan", + "keywords": [ + "PHPStan", + "contributte", + "extensions", + "rules", + "strict" + ], + "support": { + "issues": "https://github.com/contributte/phpstan/issues", + "source": "https://github.com/contributte/phpstan/tree/v0.1.0" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2023-06-04T12:37:12+00:00" + }, + { + "name": "contributte/qa", + "version": "v0.3.1", + "source": { + "type": "git", + "url": "https://github.com/contributte/qa.git", + "reference": "b2bfba8a847f52723d31b7ce67311f1226b70713" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/qa/zipball/b2bfba8a847f52723d31b7ce67311f1226b70713", + "reference": "b2bfba8a847f52723d31b7ce67311f1226b70713", + "shasum": "" + }, + "require": { + "php": ">=8.0", + "slevomat/coding-standard": "^8.12.1", + "squizlabs/php_codesniffer": "^3.7.2" + }, + "require-dev": { + "contributte/tester": "^0.2.0", + "symfony/process": "^6.0.0" + }, + "bin": [ + "bin/codesniffer", + "bin/codefixer" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.4.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Tuned & very strict coding standards for PHP projects. Trusted by Contributte, Apitte, Nettrine and many others.", + "homepage": "https://github.com/contributte/qa", + "keywords": [ + "Codestyle", + "codesniffer", + "contributte", + "qa", + "quality assurance" + ], + "support": { + "issues": "https://github.com/contributte/qa/issues", + "source": "https://github.com/contributte/qa/tree/v0.3.1" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2023-07-10T13:25:20+00:00" + }, + { + "name": "contributte/tester", + "version": "v0.3.0", + "source": { + "type": "git", + "url": "https://github.com/contributte/tester.git", + "reference": "d7db5a9b2b76910805ce191fa96b59d51c3b4dc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/contributte/tester/zipball/d7db5a9b2b76910805ce191fa96b59d51c3b4dc1", + "reference": "d7db5a9b2b76910805ce191fa96b59d51c3b4dc1", + "shasum": "" + }, + "require": { + "nette/tester": "^2.5.1", + "php": ">=8.1" + }, + "require-dev": { + "contributte/phpstan": "^0.1.0", + "contributte/qa": "^0.4.0", + "nette/di": "^3.1.2", + "nette/neon": "^3.4.0", + "nette/robot-loader": "^3.4.2" + }, + "suggest": { + "nette/di": "for NEON handling", + "nette/neon": "for NEON handling", + "nette/robot-loader": "for class finding" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Contributte\\Tester\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Nette Tester with extra horse power", + "homepage": "https://github.com/contributte/tester", + "keywords": [ + "nette", + "php", + "tester" + ], + "support": { + "issues": "https://github.com/contributte/tester/issues", + "source": "https://github.com/contributte/tester/tree/v0.3.0" + }, + "funding": [ + { + "url": "https://contributte.org/partners.html", + "type": "custom" + }, + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2023-11-17T16:10:28+00:00" + }, + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "franck.nijhof@dealerdirect.com", + "homepage": "http://www.frenck.nl", + "role": "Developer / IT Manager" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "homepage": "http://www.dealerdirect.com", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "time": "2023-01-05T11:28:13+00:00" + }, + { + "name": "nette/tester", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/nette/tester.git", + "reference": "92ad30ca60ac1e27f0c7e48b8b4e4ff1395c00c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/tester/zipball/92ad30ca60ac1e27f0c7e48b8b4e4ff1395c00c0", + "reference": "92ad30ca60ac1e27f0c7e48b8b4e4ff1395c00c0", + "shasum": "" + }, + "require": { + "php": ">=8.0 <8.4" + }, + "require-dev": { + "ext-simplexml": "*", + "phpstan/phpstan": "^1.0" + }, + "bin": [ + "src/tester" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Miloslav Hůla", + "homepage": "https://github.com/milo" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "Nette Tester: enjoyable unit testing in PHP with code coverage reporter. 🍏🍏🍎🍏", + "homepage": "https://tester.nette.org", + "keywords": [ + "Xdebug", + "assertions", + "clover", + "code coverage", + "nette", + "pcov", + "phpdbg", + "phpunit", + "testing", + "unit" + ], + "support": { + "issues": "https://github.com/nette/tester/issues", + "source": "https://github.com/nette/tester/tree/v2.5.1" + }, + "time": "2023-07-30T10:24:11+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.24.5", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "fedf211ff14ec8381c9bf5714e33a7a552dd1acc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fedf211ff14ec8381c9bf5714e33a7a552dd1acc", + "reference": "fedf211ff14ec8381c9bf5714e33a7a552dd1acc", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.5" + }, + "time": "2023-12-16T09:33:33+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "1.10.50", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4", + "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2023-12-13T10:59:42+00:00" + }, + { + "name": "phpstan/phpstan-deprecation-rules", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-deprecation-rules.git", + "reference": "089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa", + "reference": "089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.10.3" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-php-parser": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^9.5" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", + "support": { + "issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues", + "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.1.4" + }, + "time": "2023-08-05T09:02:04+00:00" + }, + { + "name": "phpstan/phpstan-nette", + "version": "1.2.9", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-nette.git", + "reference": "0e3a6805917811d685e59bb83c2286315f2f6d78" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-nette/zipball/0e3a6805917811d685e59bb83c2286315f2f6d78", + "reference": "0e3a6805917811d685e59bb83c2286315f2f6d78", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.10" + }, + "conflict": { + "nette/application": "<2.3.0", + "nette/component-model": "<2.3.0", + "nette/di": "<2.3.0", + "nette/forms": "<2.3.0", + "nette/http": "<2.3.0", + "nette/utils": "<2.3.0" + }, + "require-dev": { + "nette/application": "^3.0", + "nette/forms": "^3.0", + "nette/utils": "^2.3.0 || ^3.0.0", + "nikic/php-parser": "^4.13.2", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-php-parser": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Nette Framework class reflection extension for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-nette/issues", + "source": "https://github.com/phpstan/phpstan-nette/tree/1.2.9" + }, + "time": "2023-04-12T14:11:53+00:00" + }, + { + "name": "phpstan/phpstan-strict-rules", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-strict-rules.git", + "reference": "7a50e9662ee9f3942e4aaaf3d603653f60282542" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/7a50e9662ee9f3942e4aaaf3d603653f60282542", + "reference": "7a50e9662ee9f3942e4aaaf3d603653f60282542", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.10.34" + }, + "require-dev": { + "nikic/php-parser": "^4.13.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^9.5" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Extra strict and opinionated rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.2" + }, + "time": "2023-10-30T14:35:06+00:00" + }, + { + "name": "slevomat/coding-standard", + "version": "8.14.1", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "fea1fd6f137cc84f9cba0ae30d549615dbc6a926" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/fea1fd6f137cc84f9cba0ae30d549615dbc6a926", + "reference": "fea1fd6f137cc84f9cba0ae30d549615dbc6a926", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", + "php": "^7.2 || ^8.0", + "phpstan/phpdoc-parser": "^1.23.1", + "squizlabs/php_codesniffer": "^3.7.1" + }, + "require-dev": { + "phing/phing": "2.17.4", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpstan/phpstan": "1.10.37", + "phpstan/phpstan-deprecation-rules": "1.1.4", + "phpstan/phpstan-phpunit": "1.3.14", + "phpstan/phpstan-strict-rules": "1.5.1", + "phpunit/phpunit": "8.5.21|9.6.8|10.3.5" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.14.1" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2023-10-08T07:28:08+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.8.0", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5805f7a4e4958dbb5e944ef1e6edae0a303765e7", + "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2023-12-08T12:32:31+00:00" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": ">=8.1" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/config/config.neon b/config/config.neon new file mode 100644 index 0000000..ed751c0 --- /dev/null +++ b/config/config.neon @@ -0,0 +1,46 @@ +# ====================================== +# Config =============================== +php: + date.timezone: Europe/Prague + # session.save_path: %tempDir%/session + +# ====================================== +# Extension ============================ +extensions: + api: Contributte\Api\DI\ApiExtension + +api: + middlewares: + # Catch & handler errors + - Contributte\Api\Middleware\TracyMiddleware(%debugMode%) + # Format responses + - Contributte\Api\Middleware\NegotiationMiddleware( + Contributte\Api\Formatter\MultiFormatter([ + Contributte\Api\Formatter\JsonFormatter() + ]) + ) + # Process authentication & authorization + - Contributte\Api\Middleware\MatchMiddleware( + # skip public routes + skipTags: [public] + # apply firewall middleware + middlewares: [ + Contributte\Api\Middleware\FirewallMiddleware( + Contributte\Api\Security\StaticFirewall([ + foobar: [user: Foo, role: Bar] + ]) + ) + ] + ) + # Process controllers + - Contributte\Api\Middleware\DispatcherMiddleware + +search: + controllers: + in: %appDir%/Api + files: [*Controller.php] + +# ====================================== +# Services ============================= +services: + routing.router: App\Domain\Routing\RouterFactory::create diff --git a/config/local.neon b/config/local.neon new file mode 100644 index 0000000..e69de29 diff --git a/config/local.neon.example b/config/local.neon.example new file mode 100644 index 0000000..e69de29 diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..75a5435 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,16 @@ +includes: + - vendor/contributte/phpstan/phpstan.neon + +parameters: + level: 9 + phpVersion: 80100 + + tmpDir: %currentWorkingDirectory%/var/tmp/phpstan + + fileExtensions: + - php + - phpt + + paths: + - app + - config diff --git a/ruleset.xml b/ruleset.xml new file mode 100644 index 0000000..c259888 --- /dev/null +++ b/ruleset.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + /tests/tmp + diff --git a/tests/Cases/E2E/EntrypointTest.php b/tests/Cases/E2E/EntrypointTest.php new file mode 100644 index 0000000..2796994 --- /dev/null +++ b/tests/Cases/E2E/EntrypointTest.php @@ -0,0 +1,40 @@ +createContainer(); + $container->getByType(WebApplication::class); + + Assert::type(Container::class, $container); + } + +} + +(new EntrypointTest())->run(); diff --git a/tests/IDE/apidoc.http b/tests/IDE/apidoc.http new file mode 100644 index 0000000..56f5de8 --- /dev/null +++ b/tests/IDE/apidoc.http @@ -0,0 +1,6 @@ +### /api/_/apidoc +GET http://0.0.0.0:8000/api/_/apidoc + +> {% + client.assert(response.status === 200); +%} diff --git a/tests/IDE/ping.http b/tests/IDE/ping.http new file mode 100644 index 0000000..0b3063e --- /dev/null +++ b/tests/IDE/ping.http @@ -0,0 +1,6 @@ +### /api/_/ping +GET http://0.0.0.0:8000/api/_/ping + +> {% + client.assert(response.status === 200); +%} diff --git a/tests/IDE/product.http b/tests/IDE/product.http new file mode 100644 index 0000000..0bfeca1 --- /dev/null +++ b/tests/IDE/product.http @@ -0,0 +1,21 @@ +### /api/v1/product +GET http://0.0.0.0:8000/api/v1/product +X-Api-Key: foobar + +> {% + client.assert(response.status === 200); +%} + +### /api/v1/product +POST http://0.0.0.0:8000/api/v1/product +X-Api-Key: foobar + +{ + "uuid": "11111111-1111-1111-1111-111111111111", + "name": "Test product" +} + +### /api/v1/product/{uuid} +GET http://0.0.0.0:8000/api/v1/product/1212 +X-Api-Key: foobar + diff --git a/tests/Toolkit/Tests.php b/tests/Toolkit/Tests.php new file mode 100644 index 0000000..041e508 --- /dev/null +++ b/tests/Toolkit/Tests.php @@ -0,0 +1,12 @@ + + Options -Indexes + + +# enable cool URL + + RewriteEngine On + # RewriteBase / + + # use HTTPS + # RewriteCond %{HTTPS} !on + # RewriteRule .? https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] + + # prevents files starting with dot to be viewed by browser + RewriteRule /\.|^\.(?!well-known/) - [F] + + # front controller + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule !\.(pdf|js|ico|gif|jpg|png|css|rar|zip|tar\.gz|map)$ index.php [L] + + +# enable gzip compression + + + AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript application/json application/xml image/svg+xml + + diff --git a/www/index.php b/www/index.php new file mode 100644 index 0000000..0996575 --- /dev/null +++ b/www/index.php @@ -0,0 +1,5 @@ +