diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index d2566c1..413e796 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -9,119 +9,119 @@ on: jobs: byte_level: - name: "0️⃣ Byte-level" - runs-on: "ubuntu-latest" + name: 0️⃣ Byte-level + runs-on: ubuntu-latest steps: - - name: "Checkout code" - uses: "actions/checkout@v3" + - name: Checkout code + uses: actions/checkout@v4 - - name: "Check file permissions" + - name: Check file permissions run: | - test "$(find . -type f -not -path './.git/*' -executable)" == "" - - name: "Find non-printable ASCII characters" + test $(find . -type f -not -path './.git/*' -executable) == + - name: Find non-printable ASCII characters run: | - ! LC_ALL=C.UTF-8 find ./src -type f -name "*.php" -print0 | xargs -0 -- grep -PHn "[^ -~]" + ! LC_ALL=C.UTF-8 find ./src -type f -name *.php -print0 | xargs -0 -- grep -PHn [^ -~] syntax_errors: - name: "1️⃣ Syntax errors" - runs-on: "ubuntu-latest" + name: 1️⃣ Syntax errors + runs-on: ubuntu-latest steps: - - name: "Set up PHP" - uses: "shivammathur/setup-php@v2" + - name: Set up PHP + uses: shivammathur/setup-php@v2 with: - php-version: "latest" - tools: "parallel-lint" + php-version: latest + tools: parallel-lint - - name: "Checkout code" - uses: "actions/checkout@v3" + - name: Checkout code + uses: actions/checkout@v4 - - name: "Validate Composer configuration" - run: "composer validate --strict" + - name: Validate Composer configuration + run: composer validate --strict - - name: "Check source code for syntax errors" - run: "composer exec -- parallel-lint src/" + - name: Check source code for syntax errors + run: composer exec -- parallel-lint src/ unit_tests: - name: "2️⃣ Unit and Feature tests" + name: 2️⃣ Unit and Feature tests needs: - - "byte_level" - - "syntax_errors" - runs-on: "ubuntu-latest" + - byte_level + - syntax_errors + runs-on: ubuntu-latest strategy: matrix: php-version: - - "8.0" - - "8.1" - - "8.2" + - 8.1 + - 8.2 + - 8.3 laravel-constraint: - - "9.*" - - "10.*" + - 10.* + - 11.* dependencies: - - "lowest" - - "highest" + - lowest + - highest exclude: - - laravel-constraint: "10.*" - php-version: "8.0" + - laravel-constraint: 11.* + php-version: 8.1 steps: - - name: "Set up PHP" - uses: "shivammathur/setup-php@v2" + - name: Set up PHP + uses: shivammathur/setup-php@v2 with: - php-version: "${{ matrix.php-version }}" + php-version: ${{ matrix.php-version }} extensions: mbstring, intl coverage: xdebug - - name: "Checkout code" - uses: "actions/checkout@v3" + - name: Checkout code + uses: actions/checkout@v4 - - name: "Install dependencies" - uses: "ramsey/composer-install@v2" + - name: Install dependencies + uses: ramsey/composer-install@v3 with: - dependency-versions: "${{ matrix.dependencies }}" - composer-options: "--with=laravel/framework:${{ matrix.laravel-constraint }}" + dependency-versions: ${{ matrix.dependencies }} + composer-options: --with=laravel/framework:${{ matrix.laravel-constraint }} - - name: "Execute unit tests" - run: "composer run-script test" + - name: Execute unit tests + run: composer run-script test - - name: "Upload coverage to Codecov" - uses: "codecov/codecov-action@v3" + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 static_analysis: - name: "3️⃣ Static Analysis" + name: 3️⃣ Static Analysis needs: - - "byte_level" - - "syntax_errors" - runs-on: "ubuntu-latest" + - byte_level + - syntax_errors + runs-on: ubuntu-latest steps: - - name: "Set up PHP" - uses: "shivammathur/setup-php@v2" + - name: Set up PHP + uses: shivammathur/setup-php@v2 with: - tools: "phpstan" - php-version: "latest" - coverage: "none" + tools: phpstan + php-version: latest + coverage: none - - name: "Checkout code" - uses: "actions/checkout@v3" + - name: Checkout code + uses: actions/checkout@v4 - - name: "Install dependencies" - uses: "ramsey/composer-install@v2" + - name: Install dependencies + uses: ramsey/composer-install@v3 - - name: "Execute static analysis" - run: "composer exec -- phpstan analyze -l 5 src/" + - name: Execute static analysis + run: composer exec -- phpstan analyze -l 5 src/ exported_files: - name: "4️⃣ Exported files" + name: 4️⃣ Exported files needs: - - "byte_level" - - "syntax_errors" - runs-on: "ubuntu-latest" + - byte_level + - syntax_errors + runs-on: ubuntu-latest steps: - - name: "Checkout code" - uses: "actions/checkout@v3" + - name: Checkout code + uses: actions/checkout@v4 - - name: "Check exported files" + - name: Check exported files run: | - EXPECTED="LICENSE.md,README.md,composer.json" - CURRENT="$(git archive HEAD | tar --list --exclude="src" --exclude="src/*" --exclude=".stubs" --exclude=".stubs/*" --exclude="routes" --exclude="routes/*" --exclude="stubs" --exclude="stubs/*" --exclude="lang" --exclude="lang/*" --exclude="config" --exclude="config/*" --exclude="database" --exclude="database/*" --exclude="resources" --exclude="resources/*" | paste -s -d ",")" - echo "CURRENT =${CURRENT}" - echo "EXPECTED=${EXPECTED}" - test "${CURRENT}" == "${EXPECTED}" + EXPECTED=LICENSE.md,README.md,composer.json + CURRENT=$(git archive HEAD | tar --list --exclude=src --exclude=src/* --exclude=.stubs --exclude=.stubs/* --exclude=routes --exclude=routes/* --exclude=stubs --exclude=stubs/* --exclude=lang --exclude=lang/* --exclude=config --exclude=config/* --exclude=database --exclude=database/* --exclude=resources --exclude=resources/* | paste -s -d ,) + echo CURRENT =${CURRENT} + echo EXPECTED=${EXPECTED} + test ${CURRENT} == ${EXPECTED} diff --git a/README.md b/README.md index 30b3fe8..e531560 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Codecov coverage](https://codecov.io/gh/Laragear/Poke/branch/1.x/graph/badge.svg?token=0ELJR5X90J)](https://codecov.io/gh/Laragear/Poke) [![Maintainability](https://api.codeclimate.com/v1/badges/3954af3144475603ae67/maintainability)](https://codeclimate.com/github/Laragear/Poke/maintainability) [![Sonarcloud Status](https://sonarcloud.io/api/project_badges/measure?project=Laragear_Poke&metric=alert_status)](https://sonarcloud.io/dashboard?id=Laragear_Poke) -[![Laravel Octane Compatibility](https://img.shields.io/badge/Laravel%20Octane-Compatible-success?style=flat&logo=laravel)](https://laravel.com/docs/9.x/octane#introduction) +[![Laravel Octane Compatibility](https://img.shields.io/badge/Laravel%20Octane-Compatible-success?style=flat&logo=laravel)](https://laravel.com/docs/11.x/octane#introduction) Keep your forms alive, avoid `TokenMismatchException` by gently poking your Laravel app. @@ -16,8 +16,7 @@ Your support allows me to keep this package free, up-to-date and maintainable. A ## Requirements -* PHP 8 or later. -* Laravel 9, 10 or later. +* Laravel 10 or later. ## Installation @@ -66,6 +65,8 @@ If there is any match, this will inject the Poke script in charge to keep the fo This mode won't inject the script on error responses or redirections. +> [!INFO] +> > It's recommended to use the other modes if your application has many routes or Responses with a lot of text. ### `middleware` @@ -112,6 +113,8 @@ The `blade` mode disables middleware injection, so you can use the ` [!TIP] +> > Don't worry if you have duplicate Poke components in your view. The script is rendered only once, and even if not, the script only runs once. ## Configuration @@ -180,6 +183,8 @@ return [ ]; ``` +> [!INFO] +> > The poke routes are registered at boot time. #### Name @@ -268,4 +273,4 @@ If you discover any security related issues, please email darkghosthunter@gmail. This specific package version is licensed under the terms of the [MIT License](LICENSE.md), at time of publishing. -[Laravel](https://laravel.com) is a Trademark of [Taylor Otwell](https://github.com/TaylorOtwell/). Copyright © 2011-2023 Laravel LLC. +[Laravel](https://laravel.com) is a Trademark of [Taylor Otwell](https://github.com/TaylorOtwell/). Copyright © 2011-2024 Laravel LLC. diff --git a/composer.json b/composer.json index ab8aac0..1a2f3a5 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "Keep your forms alive, avoid TokenMismatchException by gently poking your Laravel app", "type": "library", "license": "MIT", - "minimum-stability": "stable", + "minimum-stability": "dev", "prefer-stable": true, "keywords": [ "laravel", @@ -25,17 +25,16 @@ "issues": "https://github.com/laragear/poke/issues" }, "require": { - "php": "8.*", - "laragear/meta": "^2.0.2", - "illuminate/http": "9.*|10.*", - "illuminate/routing": "9.*|10.*", - "illuminate/support": "9.*|10.*", - "illuminate/view": "9.*|10.*" + "php": "^8.1", + "laragear/meta": "3.*", + "illuminate/http": "10.*|11.*", + "illuminate/routing": "10.*|11.*", + "illuminate/support": "10.*|11.*", + "illuminate/view": "10.*|11.*" }, "require-dev": { - "laragear/meta-testing": "^1.2.2", - "orchestra/testbench": "^7.22|8.*", - "nikic/php-parser": "^4.15.3" + "laragear/meta-testing": "2.*", + "orchestra/testbench": "8.*|9.*" }, "autoload-dev": { "psr-4": { diff --git a/src/Blade/Components/Script.php b/src/Blade/Components/Script.php index 5d4d0ba..a29567b 100644 --- a/src/Blade/Components/Script.php +++ b/src/Blade/Components/Script.php @@ -2,9 +2,9 @@ namespace Laragear\Poke\Blade\Components; -use function config; use Illuminate\Contracts\View\View; use Illuminate\View\Component; +use function config; use function url; use function view; @@ -12,8 +12,6 @@ class Script extends Component { /** * Create a new component instance. - * - * @param bool $force */ public function __construct(protected bool $force = false) { @@ -21,9 +19,7 @@ public function __construct(protected bool $force = false) } /** - * Get the view / view contents that represent the component. - * - * @return \Illuminate\Contracts\View\View|string + * @inheritdoc */ public function render(): View|string { diff --git a/src/Http/Controllers/PokeController.php b/src/Http/Controllers/PokeController.php index bd60cb1..f94bccc 100644 --- a/src/Http/Controllers/PokeController.php +++ b/src/Http/Controllers/PokeController.php @@ -8,8 +8,6 @@ class PokeController { /** * Return an empty Ok response to the Poke script. - * - * @return \Illuminate\Http\Response */ public function __invoke(): Response { diff --git a/src/Http/Middleware/InjectScript.php b/src/Http/Middleware/InjectScript.php index 65c8c7f..53ff4fe 100644 --- a/src/Http/Middleware/InjectScript.php +++ b/src/Http/Middleware/InjectScript.php @@ -3,20 +3,21 @@ namespace Laragear\Poke\Http\Middleware; use Closure; -use function csrf_field; use Illuminate\Http\Request; use Illuminate\Support\Facades\Blade; use Laragear\Poke\Blade\Components\Script; +use Symfony\Component\HttpFoundation\Response; +use function csrf_field; use function strpos; use function substr_replace; -use Symfony\Component\HttpFoundation\Response; +/** + * @internal + */ class InjectScript { /** * Create a new middleware instance. - * - * @param string $mode */ public function __construct(protected string $mode) { @@ -25,11 +26,6 @@ public function __construct(protected string $mode) /** * Handle the incoming request. - * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @param string|null $force - * @return mixed */ public function handle(Request $request, Closure $next, string $force = null): mixed { @@ -44,11 +40,6 @@ public function handle(Request $request, Closure $next, string $force = null): m /** * Determine if we should inject the script into the response. - * - * @param \Illuminate\Http\Request $request - * @param \Illuminate\Http\Response $response - * @param bool $force - * @return bool */ public function shouldInject(Request $request, Response $response, bool $force): bool { @@ -68,26 +59,20 @@ public function shouldInject(Request $request, Response $response, bool $force): /** * Detect if the Response has form or CSRF Token. - * - * @param \Illuminate\Http\Response $response - * @return bool */ protected function hasCsrfInput(Response $response): bool { - return strpos($response->content(), csrf_field()); + return strpos($response->getContent(), csrf_field()); } /** * Sets the Script in the body. * - * @param \Illuminate\Http\Response $response - * @return void - * * @see https://github.com/php/php-src/blob/05023a281ddb62186fa47f51192ea51ba10f3a9b/ext/standard/string.c#L1845 */ protected function injectScript(Response $response): void { - $content = $response->content(); + $content = $response->getContent(); // With an offset of just 32 characters, we'll speed up the lookup // since the ending `` tag can be found at the end of the diff --git a/src/Http/RouteConstructor.php b/src/Http/RouteConstructor.php index 8543fe9..a3f539b 100644 --- a/src/Http/RouteConstructor.php +++ b/src/Http/RouteConstructor.php @@ -8,13 +8,13 @@ use Illuminate\Routing\Router; use Laragear\Poke\Http\Controllers\PokeController; +/** + * @internal + */ class RouteConstructor { /** * Create a new Route Generator instance. - * - * @param \Illuminate\Routing\Router $router - * @param \Illuminate\Contracts\Config\Repository $config */ public function __construct(protected Router $router, protected ConfigContract $config) { @@ -23,8 +23,6 @@ public function __construct(protected Router $router, protected ConfigContract $ /** * Construct the Poke route. - * - * @return void */ public function register(): void { @@ -46,7 +44,7 @@ public function register(): void /** * Parses the configuration. * - * @return array + * @return array{"poke.poking.route": string|null|false, "poke.poking.name": string, "poke.poking.domain": string, "poke.poking.middleware": string|string[]} */ protected function parseConfig(): array { @@ -61,8 +59,7 @@ protected function parseConfig(): array /** * Returns a Poke route. * - * @param array $config - * @return \Illuminate\Routing\Route + * @param array{"poke.poking.route": string|null|false, "poke.poking.name": string, "poke.poking.domain": string, "poke.poking.middleware": string|string[]} $config */ protected function route(array $config): Route { @@ -75,8 +72,6 @@ protected function route(array $config): Route /** * Create a new instance. - * - * @return void */ public static function construct(): void { diff --git a/src/PokeServiceProvider.php b/src/PokeServiceProvider.php index 6dafb33..a1da0c7 100644 --- a/src/PokeServiceProvider.php +++ b/src/PokeServiceProvider.php @@ -2,12 +2,15 @@ namespace Laragear\Poke; -use Illuminate\Contracts\Config\Repository; +use Illuminate\Contracts\Config\Repository as ConfigContract; use Illuminate\Contracts\Foundation\Application; -use Illuminate\Contracts\Http\Kernel; +use Illuminate\Contracts\Http\Kernel as HttpContract; use Illuminate\Routing\Router; use Illuminate\Support\ServiceProvider; +/** + * @internal + */ class PokeServiceProvider extends ServiceProvider { public const CONFIG = __DIR__.'/../config/poke.php'; @@ -32,14 +35,8 @@ static function (Application $app): Http\Middleware\InjectScript { /** * Bootstrap any application services. - * - * @param \Illuminate\Routing\Router $router - * @param \Illuminate\Contracts\Config\Repository $config - * @return void - * - * @throws \Illuminate\Contracts\Container\BindingResolutionException */ - public function boot(Router $router, Repository $config): void + public function boot(Router $router, ConfigContract $config): void { $this->loadViewsFrom(static::VIEWS, 'poke'); $this->loadViewComponentsAs('poke', [Blade\Components\Script::class]); @@ -49,7 +46,7 @@ public function boot(Router $router, Repository $config): void // If Larapoke is set to auto, push it as global middleware. if ($config->get('poke.mode') === 'auto') { - $this->app->make(Kernel::class)->appendMiddlewareToGroup('web', Http\Middleware\InjectScript::class); + $this->app->make(HttpContract::class)->appendMiddlewareToGroup('web', Http\Middleware\InjectScript::class); } if ($this->app->runningInConsole()) {