readd implementation folder
18
implementation/03/composer.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "lubiana/no-framework",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Lubiana\\NoFramework\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "example",
|
||||
"email": "test@example.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"filp/whoops": "^2.14"
|
||||
}
|
||||
}
|
BIN
implementation/03/public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
3
implementation/03/public/index.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/../src/Bootstrap.php';
|
27
implementation/03/src/Bootstrap.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework;
|
||||
|
||||
use Whoops\Handler\PrettyPageHandler;
|
||||
use Whoops\Run;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$environment = getenv('ENVIRONMENT') ?: 'dev';
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$whoops = new Run();
|
||||
|
||||
if ($environment === 'dev') {
|
||||
$whoops->pushHandler(new PrettyPageHandler());
|
||||
} else {
|
||||
$whoops->pushHandler(function (\Throwable $t) {
|
||||
error_log('ERROR: ' . $t->getMessage(), $t->getCode());
|
||||
echo 'Oooopsie';
|
||||
});
|
||||
}
|
||||
|
||||
$whoops->register();
|
||||
|
||||
echo 'Hello World!';
|
45
implementation/04/composer.json
Normal file
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"name": "lubiana/no-framework",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Lubiana\\NoFramework\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "example",
|
||||
"email": "test@example.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"filp/whoops": "^2.14"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.6",
|
||||
"symfony/var-dumper": "^6.0",
|
||||
"slevomat/coding-standard": "^7.2",
|
||||
"symplify/easy-coding-standard": "^10.2",
|
||||
"rector/rector": "^0.12.23",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.2",
|
||||
"thecodingmachine/phpstan-strict-rules": "^1.0"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"serve": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"php -S 0.0.0.0:1235 -t public"
|
||||
],
|
||||
"phpstan": "./vendor/bin/phpstan analyze",
|
||||
"baseline": "./vendor/bin/phpstan analyze --generate-baseline",
|
||||
"check": "./vendor/bin/ecs",
|
||||
"fix": "./vendor/bin/ecs --fix",
|
||||
"rector": "./vendor/bin/rector process"
|
||||
}
|
||||
}
|
872
implementation/04/composer.lock
generated
Normal file
|
@ -0,0 +1,872 @@
|
|||
{
|
||||
"_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": "92e03e1fbb1466733bb7150c4a0dec9f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "filp/whoops",
|
||||
"version": "2.14.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filp/whoops.git",
|
||||
"reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/a63e5e8f26ebbebf8ed3c5c691637325512eb0dc",
|
||||
"reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.5.9 || ^7.0 || ^8.0",
|
||||
"psr/log": "^1.0.1 || ^2.0 || ^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^0.9 || ^1.0",
|
||||
"phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3",
|
||||
"symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/var-dumper": "Pretty print complex values better with var-dumper available",
|
||||
"whoops/soap": "Formats errors as SOAP responses"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Whoops\\": "src/Whoops/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Filipe Dobreira",
|
||||
"homepage": "https://github.com/filp",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "php error handling for cool kids",
|
||||
"homepage": "https://filp.github.io/whoops/",
|
||||
"keywords": [
|
||||
"error",
|
||||
"exception",
|
||||
"handling",
|
||||
"library",
|
||||
"throwable",
|
||||
"whoops"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/filp/whoops/issues",
|
||||
"source": "https://github.com/filp/whoops/tree/2.14.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/denis-sokolov",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-01-07T12:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
|
||||
"reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Log\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for logging libraries",
|
||||
"homepage": "https://github.com/php-fig/log",
|
||||
"keywords": [
|
||||
"log",
|
||||
"psr",
|
||||
"psr-3"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/log/tree/3.0.0"
|
||||
},
|
||||
"time": "2021-07-14T16:46:02+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "dealerdirect/phpcodesniffer-composer-installer",
|
||||
"version": "v0.7.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
|
||||
"reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db",
|
||||
"reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "^1.0 || ^2.0",
|
||||
"php": ">=5.3",
|
||||
"squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/composer": "*",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3.1",
|
||||
"phpcompatibility/php-compatibility": "^9.0"
|
||||
},
|
||||
"type": "composer-plugin",
|
||||
"extra": {
|
||||
"class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Dealerdirect\\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/Dealerdirect/phpcodesniffer-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/dealerdirect/phpcodesniffer-composer-installer/issues",
|
||||
"source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer"
|
||||
},
|
||||
"time": "2022-02-04T12:51:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/extension-installer",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/extension-installer.git",
|
||||
"reference": "66c7adc9dfa38b6b5838a9fb728b68a7d8348051"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/extension-installer/zipball/66c7adc9dfa38b6b5838a9fb728b68a7d8348051",
|
||||
"reference": "66c7adc9dfa38b6b5838a9fb728b68a7d8348051",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "^1.1 || ^2.0",
|
||||
"php": "^7.1 || ^8.0",
|
||||
"phpstan/phpstan": ">=0.11.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/composer": "^1.8",
|
||||
"phing/phing": "^2.16.3",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2.0",
|
||||
"phpstan/phpstan-strict-rules": "^0.11 || ^0.12"
|
||||
},
|
||||
"type": "composer-plugin",
|
||||
"extra": {
|
||||
"class": "PHPStan\\ExtensionInstaller\\Plugin"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PHPStan\\ExtensionInstaller\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Composer plugin for automatic installation of PHPStan extensions",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/extension-installer/issues",
|
||||
"source": "https://github.com/phpstan/extension-installer/tree/1.1.0"
|
||||
},
|
||||
"time": "2020-12-13T13:06:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpdoc-parser",
|
||||
"version": "1.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||
"reference": "981cc368a216c988e862a75e526b6076987d1b50"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/981cc368a216c988e862a75e526b6076987d1b50",
|
||||
"reference": "981cc368a216c988e862a75e526b6076987d1b50",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "^1.5",
|
||||
"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.5.1"
|
||||
},
|
||||
"time": "2022-05-05T11:32:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.6.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "d76498c5531232cb8386ceb6004f7e013138d3ba"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/d76498c5531232cb8386ceb6004f7e013138d3ba",
|
||||
"reference": "d76498c5531232cb8386ceb6004f7e013138d3ba",
|
||||
"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",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.6.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/ondrejmirtes",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/phpstan",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpstan",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-10T06:54:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-strict-rules",
|
||||
"version": "1.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
|
||||
"reference": "0c82c96f2a55d8b91bbc7ee6512c94f68a206b43"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/0c82c96f2a55d8b91bbc7ee6512c94f68a206b43",
|
||||
"reference": "0c82c96f2a55d8b91bbc7ee6512c94f68a206b43",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpstan/phpstan": "^1.6.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "^4.13.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
"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.2.3"
|
||||
},
|
||||
"time": "2022-05-04T15:20:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "rector/rector",
|
||||
"version": "0.12.23",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rectorphp/rector.git",
|
||||
"reference": "690b31768b322db886b35845f8452025eba2cacb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/rectorphp/rector/zipball/690b31768b322db886b35845f8452025eba2cacb",
|
||||
"reference": "690b31768b322db886b35845f8452025eba2cacb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2|^8.0",
|
||||
"phpstan/phpstan": "^1.6"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpdoc-parser": "<1.2",
|
||||
"rector/rector-cakephp": "*",
|
||||
"rector/rector-doctrine": "*",
|
||||
"rector/rector-laravel": "*",
|
||||
"rector/rector-nette": "*",
|
||||
"rector/rector-phpoffice": "*",
|
||||
"rector/rector-phpunit": "*",
|
||||
"rector/rector-prefixed": "*",
|
||||
"rector/rector-symfony": "*"
|
||||
},
|
||||
"bin": [
|
||||
"bin/rector"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "0.12-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Instant Upgrade and Automated Refactoring of any PHP code",
|
||||
"support": {
|
||||
"issues": "https://github.com/rectorphp/rector/issues",
|
||||
"source": "https://github.com/rectorphp/rector/tree/0.12.23"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/tomasvotruba",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-01T15:50:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "slevomat/coding-standard",
|
||||
"version": "7.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/slevomat/coding-standard.git",
|
||||
"reference": "b4f96a8beea515d2d89141b7b9ad72f526d84071"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/slevomat/coding-standard/zipball/b4f96a8beea515d2d89141b7b9ad72f526d84071",
|
||||
"reference": "b4f96a8beea515d2d89141b7b9ad72f526d84071",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7",
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpstan/phpdoc-parser": "^1.5.1",
|
||||
"squizlabs/php_codesniffer": "^3.6.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phing/phing": "2.17.3",
|
||||
"php-parallel-lint/php-parallel-lint": "1.3.2",
|
||||
"phpstan/phpstan": "1.4.10|1.6.7",
|
||||
"phpstan/phpstan-deprecation-rules": "1.0.0",
|
||||
"phpstan/phpstan-phpunit": "1.0.0|1.1.1",
|
||||
"phpstan/phpstan-strict-rules": "1.2.3",
|
||||
"phpunit/phpunit": "7.5.20|8.5.21|9.5.20"
|
||||
},
|
||||
"type": "phpcodesniffer-standard",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "7.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.",
|
||||
"support": {
|
||||
"issues": "https://github.com/slevomat/coding-standard/issues",
|
||||
"source": "https://github.com/slevomat/coding-standard/tree/7.2.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/kukulich",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-06T10:58:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "3.6.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
||||
"reference": "5e4e71592f69da17871dba6e80dd51bce74a351a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a",
|
||||
"reference": "5e4e71592f69da17871dba6e80dd51bce74a351a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-simplexml": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.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": "lead"
|
||||
}
|
||||
],
|
||||
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
||||
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
|
||||
"keywords": [
|
||||
"phpcs",
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
|
||||
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
|
||||
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
|
||||
},
|
||||
"time": "2021-12-12T21:44:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.25.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825",
|
||||
"reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"provide": {
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.23-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for the Mbstring extension",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"mbstring",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-11-30T18:21:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v6.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "fa61dfb4bd3068df2492013dc65f3190e9f550c0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/fa61dfb4bd3068df2492013dc65f3190e9f550c0",
|
||||
"reference": "fa61dfb4bd3068df2492013dc65f3190e9f550c0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0.2",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"phpunit/phpunit": "<5.4.3",
|
||||
"symfony/console": "<5.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-iconv": "*",
|
||||
"symfony/console": "^5.4|^6.0",
|
||||
"symfony/process": "^5.4|^6.0",
|
||||
"symfony/uid": "^5.4|^6.0",
|
||||
"twig/twig": "^2.13|^3.0.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
|
||||
"ext-intl": "To show region name in time zone dump",
|
||||
"symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
|
||||
},
|
||||
"bin": [
|
||||
"Resources/bin/var-dump-server"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"Resources/functions/dump.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\VarDumper\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Provides mechanisms for walking through any arbitrary PHP variable",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"debug",
|
||||
"dump"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/var-dumper/tree/v6.0.8"
|
||||
},
|
||||
"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": "2022-04-26T13:22:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symplify/easy-coding-standard",
|
||||
"version": "10.2.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symplify/easy-coding-standard.git",
|
||||
"reference": "8875d8cd438756c9719fcdcc3b7d0c1d06515dd5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symplify/easy-coding-standard/zipball/8875d8cd438756c9719fcdcc3b7d0c1d06515dd5",
|
||||
"reference": "8875d8cd438756c9719fcdcc3b7d0c1d06515dd5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"conflict": {
|
||||
"friendsofphp/php-cs-fixer": "<3.0",
|
||||
"squizlabs/php_codesniffer": "<3.6"
|
||||
},
|
||||
"bin": [
|
||||
"bin/ecs"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "9.5-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Prefixed scoped version of ECS package",
|
||||
"support": {
|
||||
"source": "https://github.com/symplify/easy-coding-standard/tree/10.2.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.paypal.me/rectorphp",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/tomasvotruba",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-17T07:11:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "thecodingmachine/phpstan-strict-rules",
|
||||
"version": "v1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thecodingmachine/phpstan-strict-rules.git",
|
||||
"reference": "2ba8fa8b328c45f3b149c05def5bf96793c594b6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thecodingmachine/phpstan-strict-rules/zipball/2ba8fa8b328c45f3b149c05def5bf96793c594b6",
|
||||
"reference": "2ba8fa8b328c45f3b149c05def5bf96793c594b6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1|^8.0",
|
||||
"phpstan/phpstan": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-coveralls/php-coveralls": "^2.1",
|
||||
"phpunit/phpunit": "^7.1"
|
||||
},
|
||||
"type": "phpstan-extension",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
},
|
||||
"phpstan": {
|
||||
"includes": [
|
||||
"phpstan-strict-rules.neon"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"TheCodingMachine\\PHPStan\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "David Négrier",
|
||||
"email": "d.negrier@thecodingmachine.com"
|
||||
}
|
||||
],
|
||||
"description": "A set of additional rules for PHPStan based on best practices followed at TheCodingMachine",
|
||||
"support": {
|
||||
"issues": "https://github.com/thecodingmachine/phpstan-strict-rules/issues",
|
||||
"source": "https://github.com/thecodingmachine/phpstan-strict-rules/tree/v1.0.0"
|
||||
},
|
||||
"time": "2021-11-08T09:10:49+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
89
implementation/04/ecs.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use PhpCsFixer\Fixer\Import\OrderedImportsFixer;
|
||||
use PhpCsFixer\Fixer\Operator\NewWithBracesFixer;
|
||||
use PhpCsFixer\Fixer\PhpTag\BlankLineAfterOpeningTagFixer;
|
||||
use SlevomatCodingStandard\Sniffs\Classes\ClassConstantVisibilitySniff;
|
||||
use SlevomatCodingStandard\Sniffs\ControlStructures\NewWithoutParenthesesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\AlphabeticallySortedUsesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\DisallowGroupUseSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\MultipleUsesPerLineSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\NamespaceSpacingSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\UseSpacingSniff;
|
||||
use SlevomatCodingStandard\Sniffs\TypeHints\DeclareStrictTypesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\TypeHints\UnionTypeHintFormatSniff;
|
||||
use Symplify\EasyCodingStandard\Config\ECSConfig;
|
||||
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
|
||||
|
||||
return static function (ECSConfig $config): void {
|
||||
$config->parallel();
|
||||
$config->paths([__DIR__ . '/src', __DIR__ . '/ecs.php', __DIR__ . '/rector.php']);
|
||||
$config->skip([BlankLineAfterOpeningTagFixer::class, OrderedImportsFixer::class, NewWithBracesFixer::class]);
|
||||
|
||||
$config->sets([
|
||||
SetList::PSR_12,
|
||||
SetList::STRICT,
|
||||
SetList::ARRAY,
|
||||
SetList::SPACES,
|
||||
SetList::DOCBLOCK,
|
||||
SetList::CLEAN_CODE,
|
||||
SetList::COMMON,
|
||||
SetList::COMMENTS,
|
||||
SetList::NAMESPACES,
|
||||
SetList::SYMPLIFY,
|
||||
SetList::CONTROL_STRUCTURES,
|
||||
]);
|
||||
|
||||
// force visibility declaration on class constants
|
||||
$config->ruleWithConfiguration(ClassConstantVisibilitySniff::class, [
|
||||
'fixable' => true,
|
||||
]);
|
||||
|
||||
// sort all use statements
|
||||
$config->rules([
|
||||
AlphabeticallySortedUsesSniff::class,
|
||||
DisallowGroupUseSniff::class,
|
||||
MultipleUsesPerLineSniff::class,
|
||||
NamespaceSpacingSniff::class,
|
||||
]);
|
||||
|
||||
// import all namespaces, and event php core functions and classes
|
||||
$config->ruleWithConfiguration(
|
||||
ReferenceUsedNamesOnlySniff::class,
|
||||
[
|
||||
'allowFallbackGlobalConstants' => false,
|
||||
'allowFallbackGlobalFunctions' => false,
|
||||
'allowFullyQualifiedGlobalClasses' => false,
|
||||
'allowFullyQualifiedGlobalConstants' => false,
|
||||
'allowFullyQualifiedGlobalFunctions' => false,
|
||||
'allowFullyQualifiedNameForCollidingClasses' => true,
|
||||
'allowFullyQualifiedNameForCollidingConstants' => true,
|
||||
'allowFullyQualifiedNameForCollidingFunctions' => true,
|
||||
'searchAnnotations' => true,
|
||||
]
|
||||
);
|
||||
|
||||
// define newlines between use statements
|
||||
$config->ruleWithConfiguration(UseSpacingSniff::class, [
|
||||
'linesCountBeforeFirstUse' => 1,
|
||||
'linesCountBetweenUseTypes' => 1,
|
||||
'linesCountAfterLastUse' => 1,
|
||||
]);
|
||||
|
||||
// strict types declaration should be on same line as opening tag
|
||||
$config->ruleWithConfiguration(DeclareStrictTypesSniff::class, [
|
||||
'declareOnFirstLine' => true,
|
||||
'spacesCountAroundEqualsSign' => 0,
|
||||
]);
|
||||
|
||||
// disallow ?Foo typehint in favor of Foo|null
|
||||
$config->ruleWithConfiguration(UnionTypeHintFormatSniff::class, [
|
||||
'withSpaces' => 'no',
|
||||
'shortNullable' => 'no',
|
||||
'nullPosition' => 'last',
|
||||
]);
|
||||
|
||||
// Remove useless parentheses in new statements
|
||||
$config->rule(NewWithoutParenthesesSniff::class);
|
||||
};
|
6
implementation/04/phpstan-baseline.neon
Normal file
|
@ -0,0 +1,6 @@
|
|||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#"
|
||||
count: 1
|
||||
path: src/Bootstrap.php
|
7
implementation/04/phpstan.neon
Normal file
|
@ -0,0 +1,7 @@
|
|||
includes:
|
||||
- phpstan-baseline.neon
|
||||
|
||||
parameters:
|
||||
level: max
|
||||
paths:
|
||||
- src
|
BIN
implementation/04/public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
3
implementation/04/public/index.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/../src/Bootstrap.php';
|
11
implementation/04/rector.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use Rector\Config\RectorConfig;
|
||||
use Rector\Set\ValueObject\LevelSetList;
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
$rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/rector.php', __DIR__ . '/ecs.php']);
|
||||
$rectorConfig->importNames();
|
||||
|
||||
$rectorConfig->sets([LevelSetList::UP_TO_PHP_81]);
|
||||
};
|
34
implementation/04/src/Bootstrap.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework;
|
||||
|
||||
use Throwable;
|
||||
use Whoops\Handler\PrettyPageHandler;
|
||||
use Whoops\Run;
|
||||
|
||||
use function error_log;
|
||||
use function error_reporting;
|
||||
use function getenv;
|
||||
|
||||
use const E_ALL;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$environment = getenv('ENVIRONMENT') ?: 'dev';
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$whoops = new Run;
|
||||
|
||||
if ($environment === 'dev') {
|
||||
$whoops->pushHandler(new PrettyPageHandler);
|
||||
} else {
|
||||
$whoops->pushHandler(function (Throwable $t) {
|
||||
error_log('ERROR: ' . $t->getMessage(), $t->getCode());
|
||||
echo 'Oooopsie';
|
||||
});
|
||||
}
|
||||
|
||||
$whoops->register();
|
||||
|
||||
echo 'Hello World!';
|
46
implementation/05/composer.json
Normal file
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"name": "lubiana/no-framework",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Lubiana\\NoFramework\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "example",
|
||||
"email": "test@example.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"filp/whoops": "^2.14",
|
||||
"laminas/laminas-diactoros": "^2.11"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.6",
|
||||
"symfony/var-dumper": "^6.0",
|
||||
"slevomat/coding-standard": "^7.2",
|
||||
"symplify/easy-coding-standard": "^10.2",
|
||||
"rector/rector": "^0.12.23",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.2",
|
||||
"thecodingmachine/phpstan-strict-rules": "^1.0"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"serve": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"php -S 0.0.0.0:1235 -t public"
|
||||
],
|
||||
"phpstan": "./vendor/bin/phpstan analyze",
|
||||
"baseline": "./vendor/bin/phpstan analyze --generate-baseline",
|
||||
"check": "./vendor/bin/ecs",
|
||||
"fix": "./vendor/bin/ecs --fix",
|
||||
"rector": "./vendor/bin/rector process"
|
||||
}
|
||||
}
|
1079
implementation/05/composer.lock
generated
Normal file
89
implementation/05/ecs.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use PhpCsFixer\Fixer\Import\OrderedImportsFixer;
|
||||
use PhpCsFixer\Fixer\Operator\NewWithBracesFixer;
|
||||
use PhpCsFixer\Fixer\PhpTag\BlankLineAfterOpeningTagFixer;
|
||||
use SlevomatCodingStandard\Sniffs\Classes\ClassConstantVisibilitySniff;
|
||||
use SlevomatCodingStandard\Sniffs\ControlStructures\NewWithoutParenthesesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\AlphabeticallySortedUsesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\DisallowGroupUseSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\MultipleUsesPerLineSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\NamespaceSpacingSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\UseSpacingSniff;
|
||||
use SlevomatCodingStandard\Sniffs\TypeHints\DeclareStrictTypesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\TypeHints\UnionTypeHintFormatSniff;
|
||||
use Symplify\EasyCodingStandard\Config\ECSConfig;
|
||||
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
|
||||
|
||||
return static function (ECSConfig $config): void {
|
||||
$config->parallel();
|
||||
$config->paths([__DIR__ . '/src', __DIR__ . '/ecs.php', __DIR__ . '/rector.php']);
|
||||
$config->skip([BlankLineAfterOpeningTagFixer::class, OrderedImportsFixer::class, NewWithBracesFixer::class]);
|
||||
|
||||
$config->sets([
|
||||
SetList::PSR_12,
|
||||
SetList::STRICT,
|
||||
SetList::ARRAY,
|
||||
SetList::SPACES,
|
||||
SetList::DOCBLOCK,
|
||||
SetList::CLEAN_CODE,
|
||||
SetList::COMMON,
|
||||
SetList::COMMENTS,
|
||||
SetList::NAMESPACES,
|
||||
SetList::SYMPLIFY,
|
||||
SetList::CONTROL_STRUCTURES,
|
||||
]);
|
||||
|
||||
// force visibility declaration on class constants
|
||||
$config->ruleWithConfiguration(ClassConstantVisibilitySniff::class, [
|
||||
'fixable' => true,
|
||||
]);
|
||||
|
||||
// sort all use statements
|
||||
$config->rules([
|
||||
AlphabeticallySortedUsesSniff::class,
|
||||
DisallowGroupUseSniff::class,
|
||||
MultipleUsesPerLineSniff::class,
|
||||
NamespaceSpacingSniff::class,
|
||||
]);
|
||||
|
||||
// import all namespaces, and event php core functions and classes
|
||||
$config->ruleWithConfiguration(
|
||||
ReferenceUsedNamesOnlySniff::class,
|
||||
[
|
||||
'allowFallbackGlobalConstants' => false,
|
||||
'allowFallbackGlobalFunctions' => false,
|
||||
'allowFullyQualifiedGlobalClasses' => false,
|
||||
'allowFullyQualifiedGlobalConstants' => false,
|
||||
'allowFullyQualifiedGlobalFunctions' => false,
|
||||
'allowFullyQualifiedNameForCollidingClasses' => true,
|
||||
'allowFullyQualifiedNameForCollidingConstants' => true,
|
||||
'allowFullyQualifiedNameForCollidingFunctions' => true,
|
||||
'searchAnnotations' => true,
|
||||
]
|
||||
);
|
||||
|
||||
// define newlines between use statements
|
||||
$config->ruleWithConfiguration(UseSpacingSniff::class, [
|
||||
'linesCountBeforeFirstUse' => 1,
|
||||
'linesCountBetweenUseTypes' => 1,
|
||||
'linesCountAfterLastUse' => 1,
|
||||
]);
|
||||
|
||||
// strict types declaration should be on same line as opening tag
|
||||
$config->ruleWithConfiguration(DeclareStrictTypesSniff::class, [
|
||||
'declareOnFirstLine' => true,
|
||||
'spacesCountAroundEqualsSign' => 0,
|
||||
]);
|
||||
|
||||
// disallow ?Foo typehint in favor of Foo|null
|
||||
$config->ruleWithConfiguration(UnionTypeHintFormatSniff::class, [
|
||||
'withSpaces' => 'no',
|
||||
'shortNullable' => 'no',
|
||||
'nullPosition' => 'last',
|
||||
]);
|
||||
|
||||
// Remove useless parentheses in new statements
|
||||
$config->rule(NewWithoutParenthesesSniff::class);
|
||||
};
|
6
implementation/05/phpstan-baseline.neon
Normal file
|
@ -0,0 +1,6 @@
|
|||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#"
|
||||
count: 1
|
||||
path: src/Bootstrap.php
|
7
implementation/05/phpstan.neon
Normal file
|
@ -0,0 +1,7 @@
|
|||
includes:
|
||||
- phpstan-baseline.neon
|
||||
|
||||
parameters:
|
||||
level: max
|
||||
paths:
|
||||
- src
|
BIN
implementation/05/public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
3
implementation/05/public/index.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/../src/Bootstrap.php';
|
11
implementation/05/rector.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use Rector\Config\RectorConfig;
|
||||
use Rector\Set\ValueObject\LevelSetList;
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
$rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/rector.php', __DIR__ . '/ecs.php']);
|
||||
$rectorConfig->importNames();
|
||||
|
||||
$rectorConfig->sets([LevelSetList::UP_TO_PHP_81]);
|
||||
};
|
63
implementation/05/src/Bootstrap.php
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework;
|
||||
|
||||
use Laminas\Diactoros\Response;
|
||||
use Laminas\Diactoros\ServerRequestFactory;
|
||||
use Throwable;
|
||||
use Whoops\Handler\PrettyPageHandler;
|
||||
use Whoops\Run;
|
||||
|
||||
use function error_log;
|
||||
use function error_reporting;
|
||||
use function getenv;
|
||||
use function header;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
|
||||
use const E_ALL;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$environment = getenv('ENVIRONMENT') ?: 'dev';
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$whoops = new Run;
|
||||
|
||||
if ($environment === 'dev') {
|
||||
$whoops->pushHandler(new PrettyPageHandler);
|
||||
} else {
|
||||
$whoops->pushHandler(function (Throwable $t) {
|
||||
error_log('ERROR: ' . $t->getMessage(), $t->getCode());
|
||||
echo 'Oooopsie';
|
||||
});
|
||||
}
|
||||
|
||||
$whoops->register();
|
||||
|
||||
$request = ServerRequestFactory::fromGlobals();
|
||||
$response = new Response;
|
||||
$response->getBody()
|
||||
->write('Hello World! ');
|
||||
$response->getBody()
|
||||
->write('The Uri is: ' . $request->getUri()->getPath());
|
||||
|
||||
foreach ($response->getHeaders() as $name => $values) {
|
||||
$first = strtolower($name) !== 'set-cookie';
|
||||
foreach ($values as $value) {
|
||||
$header = sprintf('%s: %s', $name, $value);
|
||||
header($header, $first);
|
||||
$first = false;
|
||||
}
|
||||
}
|
||||
|
||||
$statusLine = sprintf(
|
||||
'HTTP/%s %s %s',
|
||||
$response->getProtocolVersion(),
|
||||
$response->getStatusCode(),
|
||||
$response->getReasonPhrase()
|
||||
);
|
||||
header($statusLine, true, $response->getStatusCode());
|
||||
|
||||
echo $response->getBody();
|
47
implementation/06/composer.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"name": "lubiana/no-framework",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Lubiana\\NoFramework\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "example",
|
||||
"email": "test@example.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"filp/whoops": "^2.14",
|
||||
"laminas/laminas-diactoros": "^2.11",
|
||||
"nikic/fast-route": "^1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.6",
|
||||
"symfony/var-dumper": "^6.0",
|
||||
"slevomat/coding-standard": "^7.2",
|
||||
"symplify/easy-coding-standard": "^10.2",
|
||||
"rector/rector": "^0.12.23",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.2",
|
||||
"thecodingmachine/phpstan-strict-rules": "^1.0"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"serve": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"php -S 0.0.0.0:1235 -t public"
|
||||
],
|
||||
"phpstan": "./vendor/bin/phpstan analyze",
|
||||
"baseline": "./vendor/bin/phpstan analyze --generate-baseline",
|
||||
"check": "./vendor/bin/ecs",
|
||||
"fix": "./vendor/bin/ecs --fix",
|
||||
"rector": "./vendor/bin/rector process"
|
||||
}
|
||||
}
|
1129
implementation/06/composer.lock
generated
Normal file
21
implementation/06/config/routes.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use FastRoute\RouteCollector;
|
||||
use Laminas\Diactoros\Response;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
return function (RouteCollector $r) {
|
||||
$r->addRoute('GET', '/hello[/{name}]', function (ServerRequestInterface $request) {
|
||||
$name = $request->getAttribute('name', 'Stranger');
|
||||
$response = (new Response)->withStatus(200);
|
||||
$response->getBody()
|
||||
->write('Hello ' . $name . '!');
|
||||
return $response;
|
||||
});
|
||||
$r->addRoute('GET', '/other', function (ServerRequestInterface $request) {
|
||||
$response = (new Response)->withStatus(200);
|
||||
$response->getBody()
|
||||
->write('This works too!');
|
||||
return $response;
|
||||
});
|
||||
};
|
89
implementation/06/ecs.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use PhpCsFixer\Fixer\Import\OrderedImportsFixer;
|
||||
use PhpCsFixer\Fixer\Operator\NewWithBracesFixer;
|
||||
use PhpCsFixer\Fixer\PhpTag\BlankLineAfterOpeningTagFixer;
|
||||
use SlevomatCodingStandard\Sniffs\Classes\ClassConstantVisibilitySniff;
|
||||
use SlevomatCodingStandard\Sniffs\ControlStructures\NewWithoutParenthesesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\AlphabeticallySortedUsesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\DisallowGroupUseSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\MultipleUsesPerLineSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\NamespaceSpacingSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\UseSpacingSniff;
|
||||
use SlevomatCodingStandard\Sniffs\TypeHints\DeclareStrictTypesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\TypeHints\UnionTypeHintFormatSniff;
|
||||
use Symplify\EasyCodingStandard\Config\ECSConfig;
|
||||
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
|
||||
|
||||
return static function (ECSConfig $config): void {
|
||||
$config->parallel();
|
||||
$config->paths([__DIR__ . '/src', __DIR__ . '/config', __DIR__ . '/ecs.php', __DIR__ . '/rector.php']);
|
||||
$config->skip([BlankLineAfterOpeningTagFixer::class, OrderedImportsFixer::class, NewWithBracesFixer::class]);
|
||||
|
||||
$config->sets([
|
||||
SetList::PSR_12,
|
||||
SetList::STRICT,
|
||||
SetList::ARRAY,
|
||||
SetList::SPACES,
|
||||
SetList::DOCBLOCK,
|
||||
SetList::CLEAN_CODE,
|
||||
SetList::COMMON,
|
||||
SetList::COMMENTS,
|
||||
SetList::NAMESPACES,
|
||||
SetList::SYMPLIFY,
|
||||
SetList::CONTROL_STRUCTURES,
|
||||
]);
|
||||
|
||||
// force visibility declaration on class constants
|
||||
$config->ruleWithConfiguration(ClassConstantVisibilitySniff::class, [
|
||||
'fixable' => true,
|
||||
]);
|
||||
|
||||
// sort all use statements
|
||||
$config->rules([
|
||||
AlphabeticallySortedUsesSniff::class,
|
||||
DisallowGroupUseSniff::class,
|
||||
MultipleUsesPerLineSniff::class,
|
||||
NamespaceSpacingSniff::class,
|
||||
]);
|
||||
|
||||
// import all namespaces, and event php core functions and classes
|
||||
$config->ruleWithConfiguration(
|
||||
ReferenceUsedNamesOnlySniff::class,
|
||||
[
|
||||
'allowFallbackGlobalConstants' => false,
|
||||
'allowFallbackGlobalFunctions' => false,
|
||||
'allowFullyQualifiedGlobalClasses' => false,
|
||||
'allowFullyQualifiedGlobalConstants' => false,
|
||||
'allowFullyQualifiedGlobalFunctions' => false,
|
||||
'allowFullyQualifiedNameForCollidingClasses' => true,
|
||||
'allowFullyQualifiedNameForCollidingConstants' => true,
|
||||
'allowFullyQualifiedNameForCollidingFunctions' => true,
|
||||
'searchAnnotations' => true,
|
||||
]
|
||||
);
|
||||
|
||||
// define newlines between use statements
|
||||
$config->ruleWithConfiguration(UseSpacingSniff::class, [
|
||||
'linesCountBeforeFirstUse' => 1,
|
||||
'linesCountBetweenUseTypes' => 1,
|
||||
'linesCountAfterLastUse' => 1,
|
||||
]);
|
||||
|
||||
// strict types declaration should be on same line as opening tag
|
||||
$config->ruleWithConfiguration(DeclareStrictTypesSniff::class, [
|
||||
'declareOnFirstLine' => true,
|
||||
'spacesCountAroundEqualsSign' => 0,
|
||||
]);
|
||||
|
||||
// disallow ?Foo typehint in favor of Foo|null
|
||||
$config->ruleWithConfiguration(UnionTypeHintFormatSniff::class, [
|
||||
'withSpaces' => 'no',
|
||||
'shortNullable' => 'no',
|
||||
'nullPosition' => 'last',
|
||||
]);
|
||||
|
||||
// Remove useless parentheses in new statements
|
||||
$config->rule(NewWithoutParenthesesSniff::class);
|
||||
};
|
6
implementation/06/phpstan-baseline.neon
Normal file
|
@ -0,0 +1,6 @@
|
|||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#"
|
||||
count: 1
|
||||
path: src/Bootstrap.php
|
8
implementation/06/phpstan.neon
Normal file
|
@ -0,0 +1,8 @@
|
|||
includes:
|
||||
- phpstan-baseline.neon
|
||||
|
||||
parameters:
|
||||
level: max
|
||||
paths:
|
||||
- src
|
||||
- config
|
BIN
implementation/06/public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
3
implementation/06/public/index.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/../src/Bootstrap.php';
|
12
implementation/06/rector.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use Rector\Config\RectorConfig;
|
||||
use Rector\Set\ValueObject\LevelSetList;
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
$rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/config', __DIR__ . '/ecs.php', __DIR__ . '/rector.php']);
|
||||
|
||||
$rectorConfig->importNames();
|
||||
|
||||
$rectorConfig->sets([LevelSetList::UP_TO_PHP_81]);
|
||||
};
|
97
implementation/06/src/Bootstrap.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework;
|
||||
|
||||
use FastRoute\Dispatcher;
|
||||
use Laminas\Diactoros\Response;
|
||||
use Laminas\Diactoros\ServerRequestFactory;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
use Whoops\Handler\PrettyPageHandler;
|
||||
use Whoops\Run;
|
||||
|
||||
use function call_user_func;
|
||||
use function error_log;
|
||||
use function error_reporting;
|
||||
use function FastRoute\simpleDispatcher;
|
||||
use function getenv;
|
||||
use function header;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
|
||||
use const E_ALL;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$environment = getenv('ENVIRONMENT') ?: 'dev';
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$whoops = new Run;
|
||||
|
||||
if ($environment === 'dev') {
|
||||
$whoops->pushHandler(new PrettyPageHandler);
|
||||
} else {
|
||||
$whoops->pushHandler(function (Throwable $t) {
|
||||
error_log('ERROR: ' . $t->getMessage(), $t->getCode());
|
||||
echo 'Oooopsie';
|
||||
});
|
||||
}
|
||||
|
||||
$whoops->register();
|
||||
|
||||
$request = ServerRequestFactory::fromGlobals();
|
||||
$response = new Response;
|
||||
$response->getBody()
|
||||
->write('Hello World! ');
|
||||
$response->getBody()
|
||||
->write('The Uri is: ' . $request->getUri()->getPath());
|
||||
|
||||
|
||||
$routeDefinitionCallback = require __DIR__ . '/../config/routes.php';
|
||||
$dispatcher = simpleDispatcher($routeDefinitionCallback);
|
||||
|
||||
$routeInfo = $dispatcher->dispatch($request->getMethod(), $request->getUri() ->getPath(),);
|
||||
|
||||
switch ($routeInfo[0]) {
|
||||
case Dispatcher::METHOD_NOT_ALLOWED:
|
||||
$response = (new Response)->withStatus(405);
|
||||
$response->getBody()
|
||||
->write('Method not allowed');
|
||||
$response = $response->withStatus(405);
|
||||
break;
|
||||
case Dispatcher::FOUND:
|
||||
$handler = $routeInfo[1];
|
||||
foreach ($routeInfo[2] as $attributeName => $attributeValue) {
|
||||
$request = $request->withAttribute($attributeName, $attributeValue);
|
||||
}
|
||||
/** @var ResponseInterface $response */
|
||||
$response = call_user_func($handler, $request);
|
||||
break;
|
||||
case Dispatcher::NOT_FOUND:
|
||||
default:
|
||||
$response = (new Response)->withStatus(404);
|
||||
$response->getBody()
|
||||
->write('Not Found!');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
foreach ($response->getHeaders() as $name => $values) {
|
||||
$first = strtolower($name) !== 'set-cookie';
|
||||
foreach ($values as $value) {
|
||||
$header = sprintf('%s: %s', $name, $value);
|
||||
header($header, $first);
|
||||
$first = false;
|
||||
}
|
||||
}
|
||||
|
||||
$statusLine = sprintf(
|
||||
'HTTP/%s %s %s',
|
||||
$response->getProtocolVersion(),
|
||||
$response->getStatusCode(),
|
||||
$response->getReasonPhrase()
|
||||
);
|
||||
header($statusLine, true, $response->getStatusCode());
|
||||
|
||||
echo $response->getBody();
|
48
implementation/07/composer.json
Normal file
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"name": "lubiana/no-framework",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Lubiana\\NoFramework\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "example",
|
||||
"email": "test@example.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"filp/whoops": "^2.14",
|
||||
"laminas/laminas-diactoros": "^2.11",
|
||||
"nikic/fast-route": "^1.3",
|
||||
"psr/http-server-handler": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.6",
|
||||
"symfony/var-dumper": "^6.0",
|
||||
"slevomat/coding-standard": "^7.2",
|
||||
"symplify/easy-coding-standard": "^10.2",
|
||||
"rector/rector": "^0.12.23",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.2",
|
||||
"thecodingmachine/phpstan-strict-rules": "^1.0"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"serve": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"php -S 0.0.0.0:1235 -t public"
|
||||
],
|
||||
"phpstan": "./vendor/bin/phpstan analyze",
|
||||
"baseline": "./vendor/bin/phpstan analyze --generate-baseline",
|
||||
"check": "./vendor/bin/ecs",
|
||||
"fix": "./vendor/bin/ecs --fix",
|
||||
"rector": "./vendor/bin/rector process"
|
||||
}
|
||||
}
|
1186
implementation/07/composer.lock
generated
Normal file
10
implementation/07/config/routes.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use FastRoute\RouteCollector;
|
||||
use Lubian\NoFramework\Action\Hello;
|
||||
use Lubian\NoFramework\Action\Other;
|
||||
|
||||
return function (RouteCollector $r) {
|
||||
$r->addRoute('GET', '/hello[/{name}]', Hello::class);
|
||||
$r->addRoute('GET', '/other', Other::class);
|
||||
};
|
89
implementation/07/ecs.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use PhpCsFixer\Fixer\Import\OrderedImportsFixer;
|
||||
use PhpCsFixer\Fixer\Operator\NewWithBracesFixer;
|
||||
use PhpCsFixer\Fixer\PhpTag\BlankLineAfterOpeningTagFixer;
|
||||
use SlevomatCodingStandard\Sniffs\Classes\ClassConstantVisibilitySniff;
|
||||
use SlevomatCodingStandard\Sniffs\ControlStructures\NewWithoutParenthesesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\AlphabeticallySortedUsesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\DisallowGroupUseSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\MultipleUsesPerLineSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\NamespaceSpacingSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\UseSpacingSniff;
|
||||
use SlevomatCodingStandard\Sniffs\TypeHints\DeclareStrictTypesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\TypeHints\UnionTypeHintFormatSniff;
|
||||
use Symplify\EasyCodingStandard\Config\ECSConfig;
|
||||
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
|
||||
|
||||
return static function (ECSConfig $config): void {
|
||||
$config->parallel();
|
||||
$config->paths([__DIR__ . '/src', __DIR__ . '/config', __DIR__ . '/ecs.php', __DIR__ . '/rector.php']);
|
||||
$config->skip([BlankLineAfterOpeningTagFixer::class, OrderedImportsFixer::class, NewWithBracesFixer::class]);
|
||||
|
||||
$config->sets([
|
||||
SetList::PSR_12,
|
||||
SetList::STRICT,
|
||||
SetList::ARRAY,
|
||||
SetList::SPACES,
|
||||
SetList::DOCBLOCK,
|
||||
SetList::CLEAN_CODE,
|
||||
SetList::COMMON,
|
||||
SetList::COMMENTS,
|
||||
SetList::NAMESPACES,
|
||||
SetList::SYMPLIFY,
|
||||
SetList::CONTROL_STRUCTURES,
|
||||
]);
|
||||
|
||||
// force visibility declaration on class constants
|
||||
$config->ruleWithConfiguration(ClassConstantVisibilitySniff::class, [
|
||||
'fixable' => true,
|
||||
]);
|
||||
|
||||
// sort all use statements
|
||||
$config->rules([
|
||||
AlphabeticallySortedUsesSniff::class,
|
||||
DisallowGroupUseSniff::class,
|
||||
MultipleUsesPerLineSniff::class,
|
||||
NamespaceSpacingSniff::class,
|
||||
]);
|
||||
|
||||
// import all namespaces, and event php core functions and classes
|
||||
$config->ruleWithConfiguration(
|
||||
ReferenceUsedNamesOnlySniff::class,
|
||||
[
|
||||
'allowFallbackGlobalConstants' => false,
|
||||
'allowFallbackGlobalFunctions' => false,
|
||||
'allowFullyQualifiedGlobalClasses' => false,
|
||||
'allowFullyQualifiedGlobalConstants' => false,
|
||||
'allowFullyQualifiedGlobalFunctions' => false,
|
||||
'allowFullyQualifiedNameForCollidingClasses' => true,
|
||||
'allowFullyQualifiedNameForCollidingConstants' => true,
|
||||
'allowFullyQualifiedNameForCollidingFunctions' => true,
|
||||
'searchAnnotations' => true,
|
||||
]
|
||||
);
|
||||
|
||||
// define newlines between use statements
|
||||
$config->ruleWithConfiguration(UseSpacingSniff::class, [
|
||||
'linesCountBeforeFirstUse' => 1,
|
||||
'linesCountBetweenUseTypes' => 1,
|
||||
'linesCountAfterLastUse' => 1,
|
||||
]);
|
||||
|
||||
// strict types declaration should be on same line as opening tag
|
||||
$config->ruleWithConfiguration(DeclareStrictTypesSniff::class, [
|
||||
'declareOnFirstLine' => true,
|
||||
'spacesCountAroundEqualsSign' => 0,
|
||||
]);
|
||||
|
||||
// disallow ?Foo typehint in favor of Foo|null
|
||||
$config->ruleWithConfiguration(UnionTypeHintFormatSniff::class, [
|
||||
'withSpaces' => 'no',
|
||||
'shortNullable' => 'no',
|
||||
'nullPosition' => 'last',
|
||||
]);
|
||||
|
||||
// Remove useless parentheses in new statements
|
||||
$config->rule(NewWithoutParenthesesSniff::class);
|
||||
};
|
6
implementation/07/phpstan-baseline.neon
Normal file
|
@ -0,0 +1,6 @@
|
|||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#"
|
||||
count: 1
|
||||
path: src/Bootstrap.php
|
8
implementation/07/phpstan.neon
Normal file
|
@ -0,0 +1,8 @@
|
|||
includes:
|
||||
- phpstan-baseline.neon
|
||||
|
||||
parameters:
|
||||
level: max
|
||||
paths:
|
||||
- src
|
||||
- config
|
BIN
implementation/07/public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
3
implementation/07/public/index.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/../src/Bootstrap.php';
|
12
implementation/07/rector.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use Rector\Config\RectorConfig;
|
||||
use Rector\Set\ValueObject\LevelSetList;
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
$rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/config', __DIR__ . '/ecs.php', __DIR__ . '/rector.php']);
|
||||
|
||||
$rectorConfig->importNames();
|
||||
|
||||
$rectorConfig->sets([LevelSetList::UP_TO_PHP_81]);
|
||||
};
|
20
implementation/07/src/Action/Hello.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Action;
|
||||
|
||||
use Laminas\Diactoros\Response;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
final class Hello implements RequestHandlerInterface
|
||||
{
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$name = $request->getAttribute('name', 'Stranger');
|
||||
$response = (new Response)->withStatus(200);
|
||||
$response->getBody()
|
||||
->write('Hello ' . $name . '!');
|
||||
return $response;
|
||||
}
|
||||
}
|
19
implementation/07/src/Action/Other.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Action;
|
||||
|
||||
use Laminas\Diactoros\Response;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
final class Other implements RequestHandlerInterface
|
||||
{
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$response = (new Response)->withStatus(200);
|
||||
$response->getBody()
|
||||
->write('This works too!');
|
||||
return $response;
|
||||
}
|
||||
}
|
101
implementation/07/src/Bootstrap.php
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework;
|
||||
|
||||
use FastRoute\Dispatcher;
|
||||
use Laminas\Diactoros\Response;
|
||||
use Laminas\Diactoros\ServerRequestFactory;
|
||||
use Lubian\NoFramework\Exception\InternalServerError;
|
||||
use Lubian\NoFramework\Exception\MethodNotAllowed;
|
||||
use Lubian\NoFramework\Exception\NotFound;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Throwable;
|
||||
use Whoops\Handler\PrettyPageHandler;
|
||||
use Whoops\Run;
|
||||
|
||||
use function assert;
|
||||
use function error_log;
|
||||
use function error_reporting;
|
||||
use function FastRoute\simpleDispatcher;
|
||||
use function getenv;
|
||||
use function header;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
|
||||
use const E_ALL;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$environment = getenv('ENVIRONMENT') ?: 'dev';
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$whoops = new Run;
|
||||
|
||||
if ($environment === 'dev') {
|
||||
$whoops->pushHandler(new PrettyPageHandler);
|
||||
} else {
|
||||
$whoops->pushHandler(function (Throwable $t) {
|
||||
error_log('ERROR: ' . $t->getMessage(), $t->getCode());
|
||||
echo 'Oooopsie';
|
||||
});
|
||||
}
|
||||
|
||||
$whoops->register();
|
||||
|
||||
$request = ServerRequestFactory::fromGlobals();
|
||||
|
||||
|
||||
$routeDefinitionCallback = require __DIR__ . '/../config/routes.php';
|
||||
$dispatcher = simpleDispatcher($routeDefinitionCallback);
|
||||
|
||||
$routeInfo = $dispatcher->dispatch($request->getMethod(), $request->getUri() ->getPath(),);
|
||||
|
||||
try {
|
||||
switch ($routeInfo[0]) {
|
||||
case Dispatcher::FOUND:
|
||||
$className = $routeInfo[1];
|
||||
$handler = new $className;
|
||||
assert($handler instanceof RequestHandlerInterface);
|
||||
foreach ($routeInfo[2] as $attributeName => $attributeValue) {
|
||||
$request = $request->withAttribute($attributeName, $attributeValue);
|
||||
}
|
||||
$response = $handler->handle($request);
|
||||
break;
|
||||
case Dispatcher::METHOD_NOT_ALLOWED:
|
||||
throw new MethodNotAllowed;
|
||||
case Dispatcher::NOT_FOUND:
|
||||
default:
|
||||
throw new NotFound;
|
||||
}
|
||||
} catch (MethodNotAllowed) {
|
||||
$response = (new Response)->withStatus(405);
|
||||
$response->getBody()
|
||||
->write('Method not Allowed');
|
||||
} catch (NotFound) {
|
||||
$response = (new Response)->withStatus(404);
|
||||
$response->getBody()
|
||||
->write('Not Found');
|
||||
} catch (Throwable $t) {
|
||||
throw new InternalServerError($t->getMessage(), $t->getCode(), $t);
|
||||
}
|
||||
|
||||
|
||||
foreach ($response->getHeaders() as $name => $values) {
|
||||
$first = strtolower($name) !== 'set-cookie';
|
||||
foreach ($values as $value) {
|
||||
$header = sprintf('%s: %s', $name, $value);
|
||||
header($header, $first);
|
||||
$first = false;
|
||||
}
|
||||
}
|
||||
|
||||
$statusLine = sprintf(
|
||||
'HTTP/%s %s %s',
|
||||
$response->getProtocolVersion(),
|
||||
$response->getStatusCode(),
|
||||
$response->getReasonPhrase()
|
||||
);
|
||||
header($statusLine, true, $response->getStatusCode());
|
||||
|
||||
echo $response->getBody();
|
9
implementation/07/src/Exception/InternalServerError.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
final class InternalServerError extends Exception
|
||||
{
|
||||
}
|
9
implementation/07/src/Exception/MethodNotAllowed.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
final class MethodNotAllowed extends Exception
|
||||
{
|
||||
}
|
9
implementation/07/src/Exception/NotFound.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
final class NotFound extends Exception
|
||||
{
|
||||
}
|
48
implementation/08/composer.json
Normal file
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"name": "lubian/no-framework",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Lubian\\NoFramework\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "example",
|
||||
"email": "test@example.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"filp/whoops": "^2.14",
|
||||
"laminas/laminas-diactoros": "^2.11",
|
||||
"nikic/fast-route": "^1.3",
|
||||
"psr/http-server-handler": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.6",
|
||||
"symfony/var-dumper": "^6.0",
|
||||
"slevomat/coding-standard": "^7.2",
|
||||
"symplify/easy-coding-standard": "^10.2",
|
||||
"rector/rector": "^0.12.23",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.2",
|
||||
"thecodingmachine/phpstan-strict-rules": "^1.0"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"serve": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"php -S 0.0.0.0:1235 -t public"
|
||||
],
|
||||
"phpstan": "./vendor/bin/phpstan analyze",
|
||||
"baseline": "./vendor/bin/phpstan analyze --generate-baseline",
|
||||
"check": "./vendor/bin/ecs",
|
||||
"fix": "./vendor/bin/ecs --fix",
|
||||
"rector": "./vendor/bin/rector process"
|
||||
}
|
||||
}
|
1186
implementation/08/composer.lock
generated
Normal file
10
implementation/08/config/routes.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use FastRoute\RouteCollector;
|
||||
use Lubian\NoFramework\Action\Hello;
|
||||
use Lubian\NoFramework\Action\Other;
|
||||
|
||||
return function (RouteCollector $r) {
|
||||
$r->addRoute('GET', '/hello[/{name}]', Hello::class);
|
||||
$r->addRoute('GET', '/other', Other::class);
|
||||
};
|
89
implementation/08/ecs.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use PhpCsFixer\Fixer\Import\OrderedImportsFixer;
|
||||
use PhpCsFixer\Fixer\Operator\NewWithBracesFixer;
|
||||
use PhpCsFixer\Fixer\PhpTag\BlankLineAfterOpeningTagFixer;
|
||||
use SlevomatCodingStandard\Sniffs\Classes\ClassConstantVisibilitySniff;
|
||||
use SlevomatCodingStandard\Sniffs\ControlStructures\NewWithoutParenthesesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\AlphabeticallySortedUsesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\DisallowGroupUseSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\MultipleUsesPerLineSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\NamespaceSpacingSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\UseSpacingSniff;
|
||||
use SlevomatCodingStandard\Sniffs\TypeHints\DeclareStrictTypesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\TypeHints\UnionTypeHintFormatSniff;
|
||||
use Symplify\EasyCodingStandard\Config\ECSConfig;
|
||||
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
|
||||
|
||||
return static function (ECSConfig $config): void {
|
||||
$config->parallel();
|
||||
$config->paths([__DIR__ . '/src', __DIR__ . '/config', __DIR__ . '/ecs.php', __DIR__ . '/rector.php']);
|
||||
$config->skip([BlankLineAfterOpeningTagFixer::class, OrderedImportsFixer::class, NewWithBracesFixer::class]);
|
||||
|
||||
$config->sets([
|
||||
SetList::PSR_12,
|
||||
SetList::STRICT,
|
||||
SetList::ARRAY,
|
||||
SetList::SPACES,
|
||||
SetList::DOCBLOCK,
|
||||
SetList::CLEAN_CODE,
|
||||
SetList::COMMON,
|
||||
SetList::COMMENTS,
|
||||
SetList::NAMESPACES,
|
||||
SetList::SYMPLIFY,
|
||||
SetList::CONTROL_STRUCTURES,
|
||||
]);
|
||||
|
||||
// force visibility declaration on class constants
|
||||
$config->ruleWithConfiguration(ClassConstantVisibilitySniff::class, [
|
||||
'fixable' => true,
|
||||
]);
|
||||
|
||||
// sort all use statements
|
||||
$config->rules([
|
||||
AlphabeticallySortedUsesSniff::class,
|
||||
DisallowGroupUseSniff::class,
|
||||
MultipleUsesPerLineSniff::class,
|
||||
NamespaceSpacingSniff::class,
|
||||
]);
|
||||
|
||||
// import all namespaces, and event php core functions and classes
|
||||
$config->ruleWithConfiguration(
|
||||
ReferenceUsedNamesOnlySniff::class,
|
||||
[
|
||||
'allowFallbackGlobalConstants' => false,
|
||||
'allowFallbackGlobalFunctions' => false,
|
||||
'allowFullyQualifiedGlobalClasses' => false,
|
||||
'allowFullyQualifiedGlobalConstants' => false,
|
||||
'allowFullyQualifiedGlobalFunctions' => false,
|
||||
'allowFullyQualifiedNameForCollidingClasses' => true,
|
||||
'allowFullyQualifiedNameForCollidingConstants' => true,
|
||||
'allowFullyQualifiedNameForCollidingFunctions' => true,
|
||||
'searchAnnotations' => true,
|
||||
]
|
||||
);
|
||||
|
||||
// define newlines between use statements
|
||||
$config->ruleWithConfiguration(UseSpacingSniff::class, [
|
||||
'linesCountBeforeFirstUse' => 1,
|
||||
'linesCountBetweenUseTypes' => 1,
|
||||
'linesCountAfterLastUse' => 1,
|
||||
]);
|
||||
|
||||
// strict types declaration should be on same line as opening tag
|
||||
$config->ruleWithConfiguration(DeclareStrictTypesSniff::class, [
|
||||
'declareOnFirstLine' => true,
|
||||
'spacesCountAroundEqualsSign' => 0,
|
||||
]);
|
||||
|
||||
// disallow ?Foo typehint in favor of Foo|null
|
||||
$config->ruleWithConfiguration(UnionTypeHintFormatSniff::class, [
|
||||
'withSpaces' => 'no',
|
||||
'shortNullable' => 'no',
|
||||
'nullPosition' => 'last',
|
||||
]);
|
||||
|
||||
// Remove useless parentheses in new statements
|
||||
$config->rule(NewWithoutParenthesesSniff::class);
|
||||
};
|
6
implementation/08/phpstan-baseline.neon
Normal file
|
@ -0,0 +1,6 @@
|
|||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#"
|
||||
count: 1
|
||||
path: src/Bootstrap.php
|
8
implementation/08/phpstan.neon
Normal file
|
@ -0,0 +1,8 @@
|
|||
includes:
|
||||
- phpstan-baseline.neon
|
||||
|
||||
parameters:
|
||||
level: max
|
||||
paths:
|
||||
- src
|
||||
- config
|
BIN
implementation/08/public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
3
implementation/08/public/index.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/../src/Bootstrap.php';
|
12
implementation/08/rector.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use Rector\Config\RectorConfig;
|
||||
use Rector\Set\ValueObject\LevelSetList;
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
$rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/config', __DIR__ . '/ecs.php', __DIR__ . '/rector.php']);
|
||||
|
||||
$rectorConfig->importNames();
|
||||
|
||||
$rectorConfig->sets([LevelSetList::UP_TO_PHP_81]);
|
||||
};
|
25
implementation/08/src/Action/Hello.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Action;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
final class Hello implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(private readonly ResponseInterface $response)
|
||||
{
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$name = $request->getAttribute('name', 'Stranger');
|
||||
$body = $this->response->getBody();
|
||||
|
||||
$body->write('Hello ' . $name . '!');
|
||||
|
||||
return $this->response->withBody($body)
|
||||
->withStatus(200);
|
||||
}
|
||||
}
|
24
implementation/08/src/Action/Other.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Action;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
final class Other implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(private readonly ResponseInterface $response)
|
||||
{
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$body = $this->response->getBody();
|
||||
|
||||
$body->write('This works too!');
|
||||
|
||||
return $this->response->withBody($body)
|
||||
->withStatus(200);
|
||||
}
|
||||
}
|
101
implementation/08/src/Bootstrap.php
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework;
|
||||
|
||||
use FastRoute\Dispatcher;
|
||||
use Laminas\Diactoros\Response;
|
||||
use Laminas\Diactoros\ServerRequestFactory;
|
||||
use Lubian\NoFramework\Exception\InternalServerError;
|
||||
use Lubian\NoFramework\Exception\MethodNotAllowed;
|
||||
use Lubian\NoFramework\Exception\NotFound;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Throwable;
|
||||
use Whoops\Handler\PrettyPageHandler;
|
||||
use Whoops\Run;
|
||||
|
||||
use function assert;
|
||||
use function error_log;
|
||||
use function error_reporting;
|
||||
use function FastRoute\simpleDispatcher;
|
||||
use function getenv;
|
||||
use function header;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
|
||||
use const E_ALL;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$environment = getenv('ENVIRONMENT') ?: 'dev';
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$whoops = new Run;
|
||||
|
||||
if ($environment === 'dev') {
|
||||
$whoops->pushHandler(new PrettyPageHandler);
|
||||
} else {
|
||||
$whoops->pushHandler(function (Throwable $t) {
|
||||
error_log('ERROR: ' . $t->getMessage(), $t->getCode());
|
||||
echo 'Oooopsie';
|
||||
});
|
||||
}
|
||||
|
||||
$whoops->register();
|
||||
|
||||
$request = ServerRequestFactory::fromGlobals();
|
||||
$response = new Response;
|
||||
|
||||
|
||||
$routeDefinitionCallback = require __DIR__ . '/../config/routes.php';
|
||||
$dispatcher = simpleDispatcher($routeDefinitionCallback);
|
||||
|
||||
$routeInfo = $dispatcher->dispatch($request->getMethod(), $request->getUri() ->getPath(),);
|
||||
|
||||
try {
|
||||
switch ($routeInfo[0]) {
|
||||
case Dispatcher::FOUND:
|
||||
$className = $routeInfo[1];
|
||||
$handler = new $className($response);
|
||||
assert($handler instanceof RequestHandlerInterface);
|
||||
foreach ($routeInfo[2] as $attributeName => $attributeValue) {
|
||||
$request = $request->withAttribute($attributeName, $attributeValue);
|
||||
}
|
||||
$response = $handler->handle($request);
|
||||
break;
|
||||
case Dispatcher::METHOD_NOT_ALLOWED:
|
||||
throw new MethodNotAllowed;
|
||||
case Dispatcher::NOT_FOUND:
|
||||
default:
|
||||
throw new NotFound;
|
||||
}
|
||||
} catch (MethodNotAllowed) {
|
||||
$response = (new Response)->withStatus(405);
|
||||
$response->getBody()
|
||||
->write('Method not Allowed');
|
||||
} catch (NotFound) {
|
||||
$response = (new Response)->withStatus(404);
|
||||
$response->getBody()
|
||||
->write('Not Found');
|
||||
} catch (Throwable $t) {
|
||||
throw new InternalServerError($t->getMessage(), $t->getCode(), $t);
|
||||
}
|
||||
|
||||
foreach ($response->getHeaders() as $name => $values) {
|
||||
$first = strtolower($name) !== 'set-cookie';
|
||||
foreach ($values as $value) {
|
||||
$header = sprintf('%s: %s', $name, $value);
|
||||
header($header, $first);
|
||||
$first = false;
|
||||
}
|
||||
}
|
||||
|
||||
$statusLine = sprintf(
|
||||
'HTTP/%s %s %s',
|
||||
$response->getProtocolVersion(),
|
||||
$response->getStatusCode(),
|
||||
$response->getReasonPhrase()
|
||||
);
|
||||
header($statusLine, true, $response->getStatusCode());
|
||||
|
||||
echo $response->getBody();
|
9
implementation/08/src/Exception/InternalServerError.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
final class InternalServerError extends Exception
|
||||
{
|
||||
}
|
9
implementation/08/src/Exception/MethodNotAllowed.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
final class MethodNotAllowed extends Exception
|
||||
{
|
||||
}
|
9
implementation/08/src/Exception/NotFound.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
final class NotFound extends Exception
|
||||
{
|
||||
}
|
48
implementation/09-wip/composer.json
Normal file
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"name": "lubian/no-framework",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Lubian\\NoFramework\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "example",
|
||||
"email": "test@example.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"filp/whoops": "^2.14",
|
||||
"laminas/laminas-diactoros": "^2.11",
|
||||
"nikic/fast-route": "^1.3",
|
||||
"psr/http-server-handler": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.6",
|
||||
"symfony/var-dumper": "^6.0",
|
||||
"slevomat/coding-standard": "^7.2",
|
||||
"symplify/easy-coding-standard": "^10.2",
|
||||
"rector/rector": "^0.12.23",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.2",
|
||||
"thecodingmachine/phpstan-strict-rules": "^1.0"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"serve": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"php -S 0.0.0.0:1235 -t public"
|
||||
],
|
||||
"phpstan": "./vendor/bin/phpstan analyze",
|
||||
"baseline": "./vendor/bin/phpstan analyze --generate-baseline",
|
||||
"check": "./vendor/bin/ecs",
|
||||
"fix": "./vendor/bin/ecs --fix",
|
||||
"rector": "./vendor/bin/rector process"
|
||||
}
|
||||
}
|
1186
implementation/09-wip/composer.lock
generated
Normal file
9
implementation/09-wip/config/container.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
$response = new \Laminas\Diactoros\Response();
|
||||
$clock = new \Lubian\NoFramework\Service\Time\SystemClock();
|
||||
|
||||
return [
|
||||
\Lubian\NoFramework\Action\Hello::class => fn () => new \Lubian\NoFramework\Action\Hello($response, $clock),
|
||||
\Lubian\NoFramework\Action\Other::class => fn () => new \Lubian\NoFramework\Action\Other($response),
|
||||
];
|
10
implementation/09-wip/config/routes.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use FastRoute\RouteCollector;
|
||||
use Lubian\NoFramework\Action\Hello;
|
||||
use Lubian\NoFramework\Action\Other;
|
||||
|
||||
return function (RouteCollector $r) {
|
||||
$r->addRoute('GET', '/hello[/{name}]', Hello::class);
|
||||
$r->addRoute('GET', '/other', Other::class);
|
||||
};
|
89
implementation/09-wip/ecs.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use PhpCsFixer\Fixer\Import\OrderedImportsFixer;
|
||||
use PhpCsFixer\Fixer\Operator\NewWithBracesFixer;
|
||||
use PhpCsFixer\Fixer\PhpTag\BlankLineAfterOpeningTagFixer;
|
||||
use SlevomatCodingStandard\Sniffs\Classes\ClassConstantVisibilitySniff;
|
||||
use SlevomatCodingStandard\Sniffs\ControlStructures\NewWithoutParenthesesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\AlphabeticallySortedUsesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\DisallowGroupUseSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\MultipleUsesPerLineSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\NamespaceSpacingSniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff;
|
||||
use SlevomatCodingStandard\Sniffs\Namespaces\UseSpacingSniff;
|
||||
use SlevomatCodingStandard\Sniffs\TypeHints\DeclareStrictTypesSniff;
|
||||
use SlevomatCodingStandard\Sniffs\TypeHints\UnionTypeHintFormatSniff;
|
||||
use Symplify\EasyCodingStandard\Config\ECSConfig;
|
||||
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
|
||||
|
||||
return static function (ECSConfig $config): void {
|
||||
$config->parallel();
|
||||
$config->paths([__DIR__ . '/src', __DIR__ . '/config', __DIR__ . '/ecs.php', __DIR__ . '/rector.php']);
|
||||
$config->skip([BlankLineAfterOpeningTagFixer::class, OrderedImportsFixer::class, NewWithBracesFixer::class]);
|
||||
|
||||
$config->sets([
|
||||
SetList::PSR_12,
|
||||
SetList::STRICT,
|
||||
SetList::ARRAY,
|
||||
SetList::SPACES,
|
||||
SetList::DOCBLOCK,
|
||||
SetList::CLEAN_CODE,
|
||||
SetList::COMMON,
|
||||
SetList::COMMENTS,
|
||||
SetList::NAMESPACES,
|
||||
SetList::SYMPLIFY,
|
||||
SetList::CONTROL_STRUCTURES,
|
||||
]);
|
||||
|
||||
// force visibility declaration on class constants
|
||||
$config->ruleWithConfiguration(ClassConstantVisibilitySniff::class, [
|
||||
'fixable' => true,
|
||||
]);
|
||||
|
||||
// sort all use statements
|
||||
$config->rules([
|
||||
AlphabeticallySortedUsesSniff::class,
|
||||
DisallowGroupUseSniff::class,
|
||||
MultipleUsesPerLineSniff::class,
|
||||
NamespaceSpacingSniff::class,
|
||||
]);
|
||||
|
||||
// import all namespaces, and event php core functions and classes
|
||||
$config->ruleWithConfiguration(
|
||||
ReferenceUsedNamesOnlySniff::class,
|
||||
[
|
||||
'allowFallbackGlobalConstants' => false,
|
||||
'allowFallbackGlobalFunctions' => false,
|
||||
'allowFullyQualifiedGlobalClasses' => false,
|
||||
'allowFullyQualifiedGlobalConstants' => false,
|
||||
'allowFullyQualifiedGlobalFunctions' => false,
|
||||
'allowFullyQualifiedNameForCollidingClasses' => true,
|
||||
'allowFullyQualifiedNameForCollidingConstants' => true,
|
||||
'allowFullyQualifiedNameForCollidingFunctions' => true,
|
||||
'searchAnnotations' => true,
|
||||
]
|
||||
);
|
||||
|
||||
// define newlines between use statements
|
||||
$config->ruleWithConfiguration(UseSpacingSniff::class, [
|
||||
'linesCountBeforeFirstUse' => 1,
|
||||
'linesCountBetweenUseTypes' => 1,
|
||||
'linesCountAfterLastUse' => 1,
|
||||
]);
|
||||
|
||||
// strict types declaration should be on same line as opening tag
|
||||
$config->ruleWithConfiguration(DeclareStrictTypesSniff::class, [
|
||||
'declareOnFirstLine' => true,
|
||||
'spacesCountAroundEqualsSign' => 0,
|
||||
]);
|
||||
|
||||
// disallow ?Foo typehint in favor of Foo|null
|
||||
$config->ruleWithConfiguration(UnionTypeHintFormatSniff::class, [
|
||||
'withSpaces' => 'no',
|
||||
'shortNullable' => 'no',
|
||||
'nullPosition' => 'last',
|
||||
]);
|
||||
|
||||
// Remove useless parentheses in new statements
|
||||
$config->rule(NewWithoutParenthesesSniff::class);
|
||||
};
|
6
implementation/09-wip/phpstan-baseline.neon
Normal file
|
@ -0,0 +1,6 @@
|
|||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#"
|
||||
count: 1
|
||||
path: src/Bootstrap.php
|
8
implementation/09-wip/phpstan.neon
Normal file
|
@ -0,0 +1,8 @@
|
|||
includes:
|
||||
- phpstan-baseline.neon
|
||||
|
||||
parameters:
|
||||
level: max
|
||||
paths:
|
||||
- src
|
||||
- config
|
BIN
implementation/09-wip/public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
3
implementation/09-wip/public/index.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/../src/Bootstrap.php';
|
12
implementation/09-wip/rector.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use Rector\Config\RectorConfig;
|
||||
use Rector\Set\ValueObject\LevelSetList;
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
$rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/config', __DIR__ . '/ecs.php', __DIR__ . '/rector.php']);
|
||||
|
||||
$rectorConfig->importNames();
|
||||
|
||||
$rectorConfig->sets([LevelSetList::UP_TO_PHP_81]);
|
||||
};
|
29
implementation/09-wip/src/Action/Hello.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Action;
|
||||
|
||||
use Lubian\NoFramework\Service\Time\Clock;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
final class Hello implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(private readonly ResponseInterface $response, private readonly Clock $clock)
|
||||
{
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$name = $request->getAttribute('name', 'Stranger');
|
||||
$body = $this->response->getBody();
|
||||
|
||||
$time = $this->clock->now()->format('H:i:s');
|
||||
|
||||
$body->write('Hello ' . $name . '!<br />');
|
||||
$body->write('The Time is: ' . $time);
|
||||
|
||||
return $this->response->withBody($body)
|
||||
->withStatus(200);
|
||||
}
|
||||
}
|
24
implementation/09-wip/src/Action/Other.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Action;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
final class Other implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(private readonly ResponseInterface $response)
|
||||
{
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$body = $this->response->getBody();
|
||||
|
||||
$body->write('This works too!');
|
||||
|
||||
return $this->response->withBody($body)
|
||||
->withStatus(200);
|
||||
}
|
||||
}
|
101
implementation/09-wip/src/Bootstrap.php
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework;
|
||||
|
||||
use FastRoute\Dispatcher;
|
||||
use Laminas\Diactoros\Response;
|
||||
use Laminas\Diactoros\ServerRequestFactory;
|
||||
use Lubian\NoFramework\Exception\InternalServerError;
|
||||
use Lubian\NoFramework\Exception\MethodNotAllowed;
|
||||
use Lubian\NoFramework\Exception\NotFound;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Throwable;
|
||||
use Whoops\Handler\PrettyPageHandler;
|
||||
use Whoops\Run;
|
||||
|
||||
use function assert;
|
||||
use function error_log;
|
||||
use function error_reporting;
|
||||
use function FastRoute\simpleDispatcher;
|
||||
use function getenv;
|
||||
use function header;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
|
||||
use const E_ALL;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$environment = getenv('ENVIRONMENT') ?: 'dev';
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$whoops = new Run;
|
||||
|
||||
if ($environment === 'dev') {
|
||||
$whoops->pushHandler(new PrettyPageHandler);
|
||||
} else {
|
||||
$whoops->pushHandler(function (Throwable $t) {
|
||||
error_log('ERROR: ' . $t->getMessage(), $t->getCode());
|
||||
echo 'Oooopsie';
|
||||
});
|
||||
}
|
||||
|
||||
$whoops->register();
|
||||
|
||||
$request = ServerRequestFactory::fromGlobals();
|
||||
$response = new Response;
|
||||
|
||||
|
||||
$routeDefinitionCallback = require __DIR__ . '/../config/routes.php';
|
||||
$dispatcher = simpleDispatcher($routeDefinitionCallback);
|
||||
|
||||
$routeInfo = $dispatcher->dispatch($request->getMethod(), $request->getUri() ->getPath(),);
|
||||
|
||||
try {
|
||||
switch ($routeInfo[0]) {
|
||||
case Dispatcher::FOUND:
|
||||
$className = $routeInfo[1];
|
||||
$handler = new $className($response);
|
||||
assert($handler instanceof RequestHandlerInterface);
|
||||
foreach ($routeInfo[2] as $attributeName => $attributeValue) {
|
||||
$request = $request->withAttribute($attributeName, $attributeValue);
|
||||
}
|
||||
$response = $handler->handle($request);
|
||||
break;
|
||||
case Dispatcher::METHOD_NOT_ALLOWED:
|
||||
throw new MethodNotAllowed;
|
||||
case Dispatcher::NOT_FOUND:
|
||||
default:
|
||||
throw new NotFound;
|
||||
}
|
||||
} catch (MethodNotAllowed) {
|
||||
$response = (new Response)->withStatus(405);
|
||||
$response->getBody()
|
||||
->write('Method not Allowed');
|
||||
} catch (NotFound) {
|
||||
$response = (new Response)->withStatus(404);
|
||||
$response->getBody()
|
||||
->write('Not Found');
|
||||
} catch (Throwable $t) {
|
||||
throw new InternalServerError($t->getMessage(), $t->getCode(), $t);
|
||||
}
|
||||
|
||||
foreach ($response->getHeaders() as $name => $values) {
|
||||
$first = strtolower($name) !== 'set-cookie';
|
||||
foreach ($values as $value) {
|
||||
$header = sprintf('%s: %s', $name, $value);
|
||||
header($header, $first);
|
||||
$first = false;
|
||||
}
|
||||
}
|
||||
|
||||
$statusLine = sprintf(
|
||||
'HTTP/%s %s %s',
|
||||
$response->getProtocolVersion(),
|
||||
$response->getStatusCode(),
|
||||
$response->getReasonPhrase()
|
||||
);
|
||||
header($statusLine, true, $response->getStatusCode());
|
||||
|
||||
echo $response->getBody();
|
|
@ -0,0 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
final class InternalServerError extends Exception
|
||||
{
|
||||
}
|
9
implementation/09-wip/src/Exception/MethodNotAllowed.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
final class MethodNotAllowed extends Exception
|
||||
{
|
||||
}
|
9
implementation/09-wip/src/Exception/NotFound.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
final class NotFound extends Exception
|
||||
{
|
||||
}
|
8
implementation/09-wip/src/Service/Time/Clock.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Service\Time;
|
||||
|
||||
interface Clock
|
||||
{
|
||||
public function now(): \DateTimeImmutable;
|
||||
}
|
12
implementation/09-wip/src/Service/Time/SystemClock.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lubian\NoFramework\Service\Time;
|
||||
|
||||
final class SystemClock implements Clock
|
||||
{
|
||||
public function now(): \DateTimeImmutable
|
||||
{
|
||||
return new \DateTimeImmutable();
|
||||
}
|
||||
|
||||
}
|