From 6b3cf7a02dff91a0c8169d268d844e56882f6423 Mon Sep 17 00:00:00 2001 From: DatPM Date: Wed, 2 Jul 2025 22:45:02 +0700 Subject: [PATCH 01/32] Preserves authenticated user context Adds a mechanism to preserve the authenticated user context when dispatching queued jobs, listeners, and notifications. Includes a trait to capture the authenticated user before serialization and a middleware to restore the context during job execution, ensuring access to the correct user. Updates test suite configuration Refactors the test suite configuration to improve reliability and reduce redundancy. - Uses a matrix strategy for PHP and Laravel versions. - Introduces stability constraints. - Removes OS matrix. - Removes unnecessary extensions. Update Name --- .github/FUNDING.yml | 2 +- .github/ISSUE_TEMPLATE/config.yml | 6 +- .github/workflows/run-tests.yml | 52 +-- CHANGELOG.md | 2 +- LICENSE.md | 2 +- README.md | 111 +++--- composer.json | 39 +- config/queueable-auth-context.php | 6 + config/skeleton.php | 6 - configure.php | 370 ------------------ database/factories/ModelFactory.php | 19 - .../migrations/create_skeleton_table.php.stub | 19 - phpstan.neon.dist | 3 +- phpunit.xml.dist | 2 +- resources/views/.gitkeep | 0 src/Commands/SkeletonCommand.php | 19 - src/Facades/Skeleton.php | 16 - src/Guards/KernelGuard.php | 22 ++ src/LaravelAuthQueueServiceProvider.php | 42 ++ .../RestoreAuthenticatedContextMiddleware.php | 44 +++ src/Skeleton.php | 5 - src/SkeletonServiceProvider.php | 25 -- src/Traits/WasAuthenticated.php | 77 ++++ tests/ArchTest.php | 5 - tests/AuthContextQueueJobTest.php | 127 ++++++ tests/AuthContextQueueListenerTest.php | 124 ++++++ tests/AuthContextQueueNotificationTest.php | 114 ++++++ tests/Controllers/TestController.php | 38 ++ tests/ExampleTest.php | 5 - tests/Jobs/TestWasAuthenticatedJob.php | 20 + tests/Jobs/TestWasNotAuthenticatedJob.php | 20 + tests/Listeners/TestEventSubscriber.php | 25 ++ tests/Models/User.php | 17 + tests/Notifications/TestNotification.php | 23 ++ tests/Pest.php | 2 +- tests/TestCase.php | 53 ++- 36 files changed, 847 insertions(+), 615 deletions(-) create mode 100644 config/queueable-auth-context.php delete mode 100644 config/skeleton.php delete mode 100644 configure.php delete mode 100644 database/factories/ModelFactory.php delete mode 100644 database/migrations/create_skeleton_table.php.stub delete mode 100644 resources/views/.gitkeep delete mode 100644 src/Commands/SkeletonCommand.php delete mode 100644 src/Facades/Skeleton.php create mode 100644 src/Guards/KernelGuard.php create mode 100644 src/LaravelAuthQueueServiceProvider.php create mode 100644 src/Middlewares/RestoreAuthenticatedContextMiddleware.php delete mode 100755 src/Skeleton.php delete mode 100644 src/SkeletonServiceProvider.php create mode 100644 src/Traits/WasAuthenticated.php delete mode 100644 tests/ArchTest.php create mode 100644 tests/AuthContextQueueJobTest.php create mode 100644 tests/AuthContextQueueListenerTest.php create mode 100644 tests/AuthContextQueueNotificationTest.php create mode 100644 tests/Controllers/TestController.php delete mode 100644 tests/ExampleTest.php create mode 100644 tests/Jobs/TestWasAuthenticatedJob.php create mode 100644 tests/Jobs/TestWasNotAuthenticatedJob.php create mode 100644 tests/Listeners/TestEventSubscriber.php create mode 100644 tests/Models/User.php create mode 100644 tests/Notifications/TestNotification.php diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index c68765b..e7e2d3d 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -github: :vendor_name +github: datpmwork diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 6474295..69f52cc 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,11 +1,11 @@ blank_issues_enabled: false contact_links: - name: Ask a question - url: https://github.com/:vendor_slug/:package_name/discussions/new?category=q-a + url: https://github.com/datpmwork/laravel-queueable-auth-context/discussions/new?category=q-a about: Ask the community for help - name: Request a feature - url: https://github.com/:vendor_slug/:package_name/discussions/new?category=ideas + url: https://github.com/datpmwork/laravel-queueable-auth-context/discussions/new?category=ideas about: Share ideas for new features - name: Report a security issue - url: https://github.com/:vendor_slug/:package_name/security/policy + url: https://github.com/datpmwork/laravel-queueable-auth-context/security/policy about: Learn how to notify us for sensitive bugs diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index adbcbe3..2f4c7ec 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -1,39 +1,25 @@ -name: run-tests +name: Tests -on: - push: - paths: - - '**.php' - - '.github/workflows/run-tests.yml' - - 'phpunit.xml.dist' - - 'composer.json' - - 'composer.lock' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true +on: [push, pull_request] jobs: test: - runs-on: ${{ matrix.os }} - timeout-minutes: 5 + runs-on: ubuntu-latest strategy: - fail-fast: true + fail-fast: false matrix: - os: [ubuntu-latest, windows-latest] - php: [8.4, 8.3] - laravel: [12.*, 11.*, 10.*] + php: [8.1, 8.2, 8.3] + laravel: [9.*, 10.*, 11.*, 12.*] stability: [prefer-lowest, prefer-stable] - include: + exclude: + - laravel: 9.* + php: 8.3 - laravel: 12.* - testbench: 10.* + php: 8.1 - laravel: 11.* - testbench: 9.* - - laravel: 10.* - testbench: 8.* - + php: 8.1 - name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} + name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} steps: - name: Checkout code @@ -43,21 +29,13 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo + extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite coverage: none - - name: Setup problem matchers - run: | - echo "::add-matcher::${{ runner.tool_cache }}/php.json" - echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - - name: Install dependencies run: | - composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update composer update --${{ matrix.stability }} --prefer-dist --no-interaction - - name: List Installed Dependencies - run: composer show -D - - name: Execute tests - run: vendor/bin/pest --ci + run: vendor/bin/pest diff --git a/CHANGELOG.md b/CHANGELOG.md index 87b3242..782a714 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,3 @@ # Changelog -All notable changes to `:package_name` will be documented in this file. +All notable changes to `laravel-queueable-auth-context` will be documented in this file. diff --git a/LICENSE.md b/LICENSE.md index 58c9ad4..c693f08 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) :vendor_name +Copyright (c) datpmwork Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 375da96..6902dab 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,91 @@ -# :package_description - -[![Latest Version on Packagist](https://img.shields.io/packagist/v/:vendor_slug/:package_slug.svg?style=flat-square)](https://packagist.org/packages/:vendor_slug/:package_slug) -[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/:vendor_slug/:package_slug/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/:vendor_slug/:package_slug/actions?query=workflow%3Arun-tests+branch%3Amain) -[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/:vendor_slug/:package_slug/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/:vendor_slug/:package_slug/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) -[![Total Downloads](https://img.shields.io/packagist/dt/:vendor_slug/:package_slug.svg?style=flat-square)](https://packagist.org/packages/:vendor_slug/:package_slug) - ---- -This repo can be used to scaffold a Laravel package. Follow these steps to get started: - -1. Press the "Use this template" button at the top of this repo to create a new repo with the contents of this skeleton. -2. Run "php ./configure.php" to run a script that will replace all placeholders throughout all the files. -3. Have fun creating your package. -4. If you need help creating a package, consider picking up our Laravel Package Training video course. ---- - -This is where your description should go. Limit it to a paragraph or two. Consider adding a small example. +# Preserve the authenticated user context when dispatching Laravel queued jobs. -## Support us +[![Latest Version on Packagist](https://img.shields.io/packagist/v/datpmwork/laravel-auth-queue.svg?style=flat-square)](https://packagist.org/packages/datpmwork/laravel-auth-queue) +[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/datpmwork/laravel-auth-queue/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/datpmwork/laravel-auth-queue/actions?query=workflow%3Arun-tests+branch%3Amain) +[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/datpmwork/laravel-auth-queue/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/datpmwork/laravel-auth-queue/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) +[![Total Downloads](https://img.shields.io/packagist/dt/datpmwork/laravel-auth-queue.svg?style=flat-square)](https://packagist.org/packages/datpmwork/laravel-auth-queue) -[](https://spatie.be/github-ad-click/:package_name) +This package preserves the authenticated user context when dispatching Laravel queued jobs, notifications, or event +listeners. -We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). +It allows you to seamlessly access the authenticated user who originally dispatched the job through Laravel's +auth() manager when the job is being handled. -We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). +This is particularly useful when you need to maintain user context across +asynchronous operations. -## Installation +## Support us -You can install the package via composer: +You can support this project via [GitHub Sponsors](https://github.com/sponsors/datpmwork). -```bash -composer require :vendor_slug/:package_slug -``` +## Installation -You can publish and run the migrations with: +You can install the package via composer: ```bash -php artisan vendor:publish --tag=":package_slug-migrations" -php artisan migrate +composer require datpmwork/laravel-auth-queue ``` -You can publish the config file with: - -```bash -php artisan vendor:publish --tag=":package_slug-config" -``` +## Usage -This is the contents of the published config file: +Add `WasAuthenticated` trait to any `Job`, `Notification`, `Listener` which need to access `auth` data when the Job was dispatched +### Example Job ```php -return [ -]; +class SampleJob implements ShouldQueue +{ + use Dispatchable, InteractsWithQueue, Queueable, WasAuthenticated; + + public function handle() + { + # auth()->user() was the authenticated user who dispatched this job + logger()->info('Auth ID: '. auth()->id()); + } +} ``` -Optionally, you can publish the views using - -```bash -php artisan vendor:publish --tag=":package_slug-views" +### Example Notification +```php +class SampleNotification extends Notification implements ShouldQueue +{ + use Queueable, WasAuthenticated; + + public function via(): array + { + return ['database']; + } + + public function toDatabase(): array + { + # auth()->user() was the authenticated user who triggered this notification + return [auth()->id()]; + } +} ``` -## Usage - +### Example Subscriber ```php -$variable = new VendorName\Skeleton(); -echo $variable->echoPhrase('Hello, VendorName!'); +class SampleSubscriber implements ShouldQueue +{ + use Queueable, WasAuthenticated; + + public function subscribe(Dispatcher $dispatcher) + { + $dispatcher->listen('eloquent.updated: ' . User::class, [self::class, 'onUserUpdated']); + } + + public function onUserUpdated(User $user) + { + # auth()->user() was the authenticated user who triggered this event + logger()->info('Auth ID: '. auth()->id()); + } +} ``` ## Testing ```bash -composer test +./vendor/bin/pest ``` ## Changelog @@ -85,7 +102,7 @@ Please review [our security policy](../../security/policy) on how to report secu ## Credits -- [:author_name](https://github.com/:author_username) +- [datpmwork](https://github.com/datpmwork) - [All Contributors](../../contributors) ## License diff --git a/composer.json b/composer.json index 8f9b850..845625f 100644 --- a/composer.json +++ b/composer.json @@ -1,48 +1,44 @@ { - "name": ":vendor_slug/:package_slug", - "description": ":package_description", + "name": "datpmwork/laravel-auth-queue", + "description": "Preserve the authenticated user context when dispatching Laravel queued jobs.", "keywords": [ - ":vendor_name", + "datpmwork", "laravel", - ":package_slug" + "laravel-queueable-auth-context" ], - "homepage": "https://github.com/:vendor_slug/:package_slug", + "homepage": "https://github.com/datpmwork/laravel-auth-queue", "license": "MIT", "authors": [ { - "name": ":author_name", - "email": "author@domain.com", - "role": "Developer" + "name": "datpmwork", + "email": "datpm@datpm.work", + "role": "Owner" } ], "require": { - "php": "^8.4", - "spatie/laravel-package-tools": "^1.16", - "illuminate/contracts": "^10.0||^11.0||^12.0" + "php": "^8.1", + "illuminate/support": "^9.0|^10.0|^11.0|^12.0" }, "require-dev": { "laravel/pint": "^1.14", "nunomaduro/collision": "^8.1.1||^7.10.0", "larastan/larastan": "^2.9||^3.0", - "orchestra/testbench": "^10.0.0||^9.0.0||^8.22.0", + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", "pestphp/pest": "^3.0", "pestphp/pest-plugin-arch": "^3.0", "pestphp/pest-plugin-laravel": "^3.0", "phpstan/extension-installer": "^1.3||^2.0", "phpstan/phpstan-deprecation-rules": "^1.1||^2.0", - "phpstan/phpstan-phpunit": "^1.3||^2.0", - "spatie/laravel-ray": "^1.35" + "phpstan/phpstan-phpunit": "^1.3||^2.0" }, "autoload": { "psr-4": { - "VendorName\\Skeleton\\": "src/", - "VendorName\\Skeleton\\Database\\Factories\\": "database/factories/" + "DatPM\\LaravelAuthQueue\\": "src/" } }, "autoload-dev": { "psr-4": { - "VendorName\\Skeleton\\Tests\\": "tests/", - "Workbench\\App\\": "workbench/app/" + "DatPM\\LaravelAuthQueue\\Tests\\": "tests/" } }, "scripts": { @@ -63,11 +59,8 @@ "extra": { "laravel": { "providers": [ - "VendorName\\Skeleton\\SkeletonServiceProvider" - ], - "aliases": { - "Skeleton": "VendorName\\Skeleton\\Facades\\Skeleton" - } + "DatPM\\LaravelAuthQueue\\LaravelAuthQueueServiceProvider" + ] } }, "minimum-stability": "dev", diff --git a/config/queueable-auth-context.php b/config/queueable-auth-context.php new file mode 100644 index 0000000..d015b59 --- /dev/null +++ b/config/queueable-auth-context.php @@ -0,0 +1,6 @@ + $version) { - if (in_array($name, $names, true)) { - unset($data['require-dev'][$name]); - } - } - - file_put_contents(__DIR__.'/composer.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); -} - -function remove_composer_script($scriptName) -{ - $data = json_decode(file_get_contents(__DIR__.'/composer.json'), true); - - foreach ($data['scripts'] as $name => $script) { - if ($scriptName === $name) { - unset($data['scripts'][$name]); - break; - } - } - - file_put_contents(__DIR__.'/composer.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); -} - -function remove_readme_paragraphs(string $file): void -{ - $contents = file_get_contents($file); - - file_put_contents( - $file, - preg_replace('/.*/s', '', $contents) ?: $contents - ); -} - -function safeUnlink(string $filename) -{ - if (file_exists($filename) && is_file($filename)) { - unlink($filename); - } -} - -function determineSeparator(string $path): string -{ - return str_replace('/', DIRECTORY_SEPARATOR, $path); -} - -function replaceForWindows(): array -{ - return preg_split('/\\r\\n|\\r|\\n/', run('dir /S /B * | findstr /v /i .git\ | findstr /v /i vendor | findstr /v /i '.basename(__FILE__).' | findstr /r /i /M /F:/ ":author :vendor :package VendorName skeleton migration_table_name vendor_name vendor_slug author@domain.com"')); -} - -function replaceForAllOtherOSes(): array -{ - return explode(PHP_EOL, run('grep -E -r -l -i ":author|:vendor|:package|VendorName|skeleton|migration_table_name|vendor_name|vendor_slug|author@domain.com" --exclude-dir=vendor ./* ./.github/* | grep -v '.basename(__FILE__))); -} - -function getGitHubApiEndpoint(string $endpoint): ?stdClass -{ - try { - $curl = curl_init("https://api.github.com/{$endpoint}"); - curl_setopt_array($curl, [ - CURLOPT_RETURNTRANSFER => true, - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_HTTPGET => true, - CURLOPT_HTTPHEADER => [ - 'User-Agent: spatie-configure-script/1.0', - ], - ]); - - $response = curl_exec($curl); - $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); - - curl_close($curl); - - if ($statusCode === 200) { - return json_decode($response); - } - } catch (Exception $e) { - // ignore - } - - return null; -} - -function searchCommitsForGitHubUsername(): string -{ - $authorName = strtolower(trim(shell_exec('git config user.name'))); - - $committersRaw = shell_exec("git log --author='@users.noreply.github.com' --pretty='%an:%ae' --reverse"); - $committersLines = explode("\n", $committersRaw ?? ''); - $committers = array_filter(array_map(function ($line) use ($authorName) { - $line = trim($line); - [$name, $email] = explode(':', $line) + [null, null]; - - return [ - 'name' => $name, - 'email' => $email, - 'isMatch' => strtolower($name) === $authorName && ! str_contains($name, '[bot]'), - ]; - }, $committersLines), fn ($item) => $item['isMatch']); - - if (empty($committers)) { - return ''; - } - - $firstCommitter = reset($committers); - - return explode('@', $firstCommitter['email'])[0] ?? ''; -} - -function guessGitHubUsernameUsingCli() -{ - try { - if (preg_match('/ogged in to github\.com as ([a-zA-Z-_]+).+/', shell_exec('gh auth status -h github.com 2>&1'), $matches)) { - return $matches[1]; - } - } catch (Exception $e) { - // ignore - } - - return ''; -} - -function guessGitHubUsername(): string -{ - $username = searchCommitsForGitHubUsername(); - if (! empty($username)) { - return $username; - } - - $username = guessGitHubUsernameUsingCli(); - if (! empty($username)) { - return $username; - } - - // fall back to using the username from the git remote - $remoteUrl = shell_exec('git config remote.origin.url') ?? ''; - $remoteUrlParts = explode('/', str_replace(':', '/', trim($remoteUrl))); - - return $remoteUrlParts[1] ?? ''; -} - -function guessGitHubVendorInfo($authorName, $username): array -{ - $remoteUrl = shell_exec('git config remote.origin.url') ?? ''; - $remoteUrlParts = explode('/', str_replace(':', '/', trim($remoteUrl))); - - if (! isset($remoteUrlParts[1])) { - return [$authorName, $username]; - } - - $response = getGitHubApiEndpoint("orgs/{$remoteUrlParts[1]}"); - - if ($response === null) { - return [$authorName, $username]; - } - - return [$response->name ?? $authorName, $response->login ?? $username]; -} - -$gitName = run('git config user.name'); -$authorName = ask('Author name', $gitName); - -$gitEmail = run('git config user.email'); -$authorEmail = ask('Author email', $gitEmail); -$authorUsername = ask('Author username', guessGitHubUsername()); - -$guessGitHubVendorInfo = guessGitHubVendorInfo($authorName, $authorUsername); - -$vendorName = ask('Vendor name', $guessGitHubVendorInfo[0]); -$vendorUsername = ask('Vendor username', $guessGitHubVendorInfo[1] ?? slugify($vendorName)); -$vendorSlug = slugify($vendorUsername); - -$vendorNamespace = str_replace('-', '', ucwords($vendorName)); -$vendorNamespace = ask('Vendor namespace', $vendorNamespace); - -$currentDirectory = getcwd(); -$folderName = basename($currentDirectory); - -$packageName = ask('Package name', $folderName); -$packageSlug = slugify($packageName); -$packageSlugWithoutPrefix = remove_prefix('laravel-', $packageSlug); - -$className = title_case($packageName); -$className = ask('Class name', $className); -$variableName = lcfirst($className); -$description = ask('Package description', "This is my package {$packageSlug}"); - -$usePhpStan = confirm('Enable PhpStan?', true); -$useLaravelPint = confirm('Enable Laravel Pint?', true); -$useDependabot = confirm('Enable Dependabot?', true); -$useLaravelRay = confirm('Use Ray for debugging?', true); -$useUpdateChangelogWorkflow = confirm('Use automatic changelog updater workflow?', true); - -writeln('------'); -writeln("Author : {$authorName} ({$authorUsername}, {$authorEmail})"); -writeln("Vendor : {$vendorName} ({$vendorSlug})"); -writeln("Package : {$packageSlug} <{$description}>"); -writeln("Namespace : {$vendorNamespace}\\{$className}"); -writeln("Class name : {$className}"); -writeln('---'); -writeln('Packages & Utilities'); -writeln('Use Laravel/Pint : '.($useLaravelPint ? 'yes' : 'no')); -writeln('Use Larastan/PhpStan : '.($usePhpStan ? 'yes' : 'no')); -writeln('Use Dependabot : '.($useDependabot ? 'yes' : 'no')); -writeln('Use Ray App : '.($useLaravelRay ? 'yes' : 'no')); -writeln('Use Auto-Changelog : '.($useUpdateChangelogWorkflow ? 'yes' : 'no')); -writeln('------'); - -writeln('This script will replace the above values in all relevant files in the project directory.'); - -if (! confirm('Modify files?', true)) { - exit(1); -} - -$files = (str_starts_with(strtoupper(PHP_OS), 'WIN') ? replaceForWindows() : replaceForAllOtherOSes()); - -foreach ($files as $file) { - replace_in_file($file, [ - ':author_name' => $authorName, - ':author_username' => $authorUsername, - 'author@domain.com' => $authorEmail, - ':vendor_name' => $vendorName, - ':vendor_slug' => $vendorSlug, - 'VendorName' => $vendorNamespace, - ':package_name' => $packageName, - ':package_slug' => $packageSlug, - ':package_slug_without_prefix' => $packageSlugWithoutPrefix, - 'Skeleton' => $className, - 'skeleton' => $packageSlug, - 'migration_table_name' => title_snake($packageSlug), - 'variable' => $variableName, - ':package_description' => $description, - ]); - - match (true) { - str_contains($file, determineSeparator('src/Skeleton.php')) => rename($file, determineSeparator('./src/'.$className.'.php')), - str_contains($file, determineSeparator('src/SkeletonServiceProvider.php')) => rename($file, determineSeparator('./src/'.$className.'ServiceProvider.php')), - str_contains($file, determineSeparator('src/Facades/Skeleton.php')) => rename($file, determineSeparator('./src/Facades/'.$className.'.php')), - str_contains($file, determineSeparator('src/Commands/SkeletonCommand.php')) => rename($file, determineSeparator('./src/Commands/'.$className.'Command.php')), - str_contains($file, determineSeparator('database/migrations/create_skeleton_table.php.stub')) => rename($file, determineSeparator('./database/migrations/create_'.title_snake($packageSlugWithoutPrefix).'_table.php.stub')), - str_contains($file, determineSeparator('config/skeleton.php')) => rename($file, determineSeparator('./config/'.$packageSlugWithoutPrefix.'.php')), - str_contains($file, 'README.md') => remove_readme_paragraphs($file), - default => [], - }; -} - -if (! $useLaravelPint) { - safeUnlink(__DIR__.'/.github/workflows/fix-php-code-style-issues.yml'); - safeUnlink(__DIR__.'/pint.json'); -} - -if (! $usePhpStan) { - safeUnlink(__DIR__.'/phpstan.neon.dist'); - safeUnlink(__DIR__.'/phpstan-baseline.neon'); - safeUnlink(__DIR__.'/.github/workflows/phpstan.yml'); - - remove_composer_deps([ - 'phpstan/extension-installer', - 'phpstan/phpstan-deprecation-rules', - 'phpstan/phpstan-phpunit', - 'larastan/larastan', - ]); - - remove_composer_script('phpstan'); -} - -if (! $useDependabot) { - safeUnlink(__DIR__.'/.github/dependabot.yml'); - safeUnlink(__DIR__.'/.github/workflows/dependabot-auto-merge.yml'); -} - -if (! $useLaravelRay) { - remove_composer_deps(['spatie/laravel-ray']); -} - -if (! $useUpdateChangelogWorkflow) { - safeUnlink(__DIR__.'/.github/workflows/update-changelog.yml'); -} - -confirm('Execute `composer install` and run tests?') && run('composer install && composer test'); - -confirm('Let this script delete itself?', true) && unlink(__FILE__); diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php deleted file mode 100644 index c51604f..0000000 --- a/database/factories/ModelFactory.php +++ /dev/null @@ -1,19 +0,0 @@ -id(); - - // add fields - - $table->timestamps(); - }); - } -}; diff --git a/phpstan.neon.dist b/phpstan.neon.dist index ab1b4c3..5fc50b3 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,7 +6,8 @@ parameters: paths: - src - config - - database + excludePaths: + - tests/* tmpDir: build/phpstan checkOctaneCompatibility: true checkModelProperties: true diff --git a/phpunit.xml.dist b/phpunit.xml.dist index bfe434d..6940fc5 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -16,7 +16,7 @@ backupStaticProperties="false" > - + tests diff --git a/resources/views/.gitkeep b/resources/views/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/Commands/SkeletonCommand.php b/src/Commands/SkeletonCommand.php deleted file mode 100644 index 3e5f628..0000000 --- a/src/Commands/SkeletonCommand.php +++ /dev/null @@ -1,19 +0,0 @@ -comment('All done'); - - return self::SUCCESS; - } -} diff --git a/src/Facades/Skeleton.php b/src/Facades/Skeleton.php deleted file mode 100644 index 571a498..0000000 --- a/src/Facades/Skeleton.php +++ /dev/null @@ -1,16 +0,0 @@ -user; + } + + public function validate(array $credentials = []) + { + throw new Exception('Invalid calls in KernelGuard'); + } +} diff --git a/src/LaravelAuthQueueServiceProvider.php b/src/LaravelAuthQueueServiceProvider.php new file mode 100644 index 0000000..7205667 --- /dev/null +++ b/src/LaravelAuthQueueServiceProvider.php @@ -0,0 +1,42 @@ +app->runningInConsole()) { + return; + } + + # Register new AuthGuard for Kernel Application + Auth::extend('kernel', function () { + return new KernelGuard(); + }); + + # Add a new KernelGuard to support authenticated in CLI + $defaultGuard = config('auth.defaults.guard'); + + config(['auth.guards.kernel' => [ + 'driver' => 'kernel', + 'provider' => config("auth.guards.{$defaultGuard}.provider"), + ]]); + } + + public function configurePackage(Package $package): void + { + /* + * This class is a Package Service Provider + * + * More info: https://github.com/spatie/laravel-package-tools + */ + $package->name('laravel-queueable-auth-context'); + } +} diff --git a/src/Middlewares/RestoreAuthenticatedContextMiddleware.php b/src/Middlewares/RestoreAuthenticatedContextMiddleware.php new file mode 100644 index 0000000..e28aa4e --- /dev/null +++ b/src/Middlewares/RestoreAuthenticatedContextMiddleware.php @@ -0,0 +1,44 @@ +authUser = $authUser; + } + + public function handle($command, callable $next) + { + Auth::shouldUse('kernel'); + + $guard = auth(); + + if (!empty($this->authUser)) { + $guard->setUser($this->authUser); + } + + $response = $next($command); + + $guard->forgetUser(); + + return $response; + } + + /** + * @return Authenticatable|null + */ + public function getAuthUser() + { + return $this->authUser; + } +} diff --git a/src/Skeleton.php b/src/Skeleton.php deleted file mode 100755 index 34c7194..0000000 --- a/src/Skeleton.php +++ /dev/null @@ -1,5 +0,0 @@ -name('skeleton') - ->hasConfigFile() - ->hasViews() - ->hasMigration('create_migration_table_name_table') - ->hasCommand(SkeletonCommand::class); - } -} diff --git a/src/Traits/WasAuthenticated.php b/src/Traits/WasAuthenticated.php new file mode 100644 index 0000000..f4f1325 --- /dev/null +++ b/src/Traits/WasAuthenticated.php @@ -0,0 +1,77 @@ +captureAuthContext(); + + // If using SerializesModels, call its __sleep method + if (in_array('Illuminate\Queue\SerializesModels', class_uses_recursive($this))) { + // Let SerializesModels handle its serialization + $properties = $this->__sleepSerializesModels(); + } else { + // Standard serialization + $properties = array_keys(get_object_vars($this)); + } + + return $properties; + } + + /** + * Handle SerializesModels __sleep if trait is used + */ + protected function __sleepSerializesModels() + { + $properties = array_keys(get_object_vars($this)); + + // Let SerializesModels do its magic + foreach ($properties as $property) { + $value = $this->{$property}; + if ($this->isSerializableModel($value)) { + $this->{$property} = $this->getSerializedPropertyValue($value); + } + } + + return $properties; + } + + /** + * Check if value should be serialized by SerializesModels + */ + protected function isSerializableModel($value) + { + return method_exists($this, 'getSerializedPropertyValue') && + (is_object($value) && method_exists($value, 'getQueueableId')); + } + + /** + * Capture and customize auth context + */ + protected function captureAuthContext() + { + $user = auth()->user(); + if ($user) { + // Customize serialization based on your needs + $this->authenticatedUser = $user; + } + } + + /** + * The job should go through AuthenticatedMiddleware + */ + public function middleware() + { + return [new RestoreAuthenticatedContextMiddleware($this->authenticatedUser ?: auth()->user())]; + } +} diff --git a/tests/ArchTest.php b/tests/ArchTest.php deleted file mode 100644 index 87fb64c..0000000 --- a/tests/ArchTest.php +++ /dev/null @@ -1,5 +0,0 @@ -expect(['dd', 'dump', 'ray']) - ->each->not->toBeUsed(); diff --git a/tests/AuthContextQueueJobTest.php b/tests/AuthContextQueueJobTest.php new file mode 100644 index 0000000..be30462 --- /dev/null +++ b/tests/AuthContextQueueJobTest.php @@ -0,0 +1,127 @@ +id(); + $table->string('name'); + $table->string('email'); + }); + + // Register test routes + Route::middleware('api')->group(function () { + Route::post('/test/dispatch-job', [ + TestController::class, + 'dispatchJob', + ]); + }); +}); + +it('preserves auth context when Job is dispatched', function () { + Queue::fake()->serializeAndRestore(); + + /** @var \Mockery\Mock $loggerSpy */ + $loggerSpy = Mockery::spy('logger'); + $this->app->instance('log', $loggerSpy); + + // Arrange + $user = User::create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + // Act + $response = $this->actingAs($user)->postJson('/test/dispatch-job'); + + // Assert + $response->assertSuccessful(); + + Queue::assertCount(2); + + Queue::assertPushed(TestWasAuthenticatedJob::class, function (TestWasAuthenticatedJob $job) use ($user) { + return collect($job->middleware)->filter(function ($middleware) use ($user) { + return get_class($middleware) === RestoreAuthenticatedContextMiddleware::class && + $middleware->getAuthUser()->getAuthIdentifier() === $user->getKey(); + }); + }); + Queue::assertPushed(TestWasNotAuthenticatedJob::class, 1); +}); + +it('preserves auth context when Job is executed', function () { + Queue::setDefaultDriver('database'); + + /** @var \Mockery\Mock $loggerSpy */ + $loggerSpy = Mockery::spy('logger'); + $this->app->instance('log', $loggerSpy); + + // Arrange + $user = User::create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + // Act + $response = $this->actingAs($user)->postJson('/test/dispatch-job'); + + // Assert + $response->assertSuccessful(); + + expect(DB::table('jobs')->count())->toBe(2); + + # Reset Auth to prevent reuse auth data of the above API + auth()->guard()->forgetUser(); + + $this->artisan('queue:work --once'); + + // Assert logger was called with correct values + $loggerSpy->shouldHaveReceived('info') + ->with("Auth ID: {$user->id}") + ->once(); + + $loggerSpy->shouldHaveReceived('info') + ->with("Auth Check: 1") + ->once(); + + $this->artisan('queue:work --once'); + + // Assert logger was called with correct values + $loggerSpy->shouldHaveReceived('info') + ->with("Auth ID: ") + ->once(); + + $loggerSpy->shouldHaveReceived('info') + ->with('Auth Check: ') + ->once(); +}); + +it('handles unauthenticated requests correctly', function () { + // Arrange + Queue::fake()->serializeAndRestore(); + + // Act + $response = $this->postJson('/test/dispatch-job'); + + // Assert + $response->assertSuccessful(); + + Queue::assertPushed(TestWasAuthenticatedJob::class, function (TestWasAuthenticatedJob $job) { + return collect($job->middleware)->filter(function ($middleware) { + return get_class($middleware) === RestoreAuthenticatedContextMiddleware::class && + empty($middleware->getAuthUser()); + }); + }); +}); + +afterEach(function () { + Schema::dropIfExists('users'); + DB::table('jobs')->delete(); +}); diff --git a/tests/AuthContextQueueListenerTest.php b/tests/AuthContextQueueListenerTest.php new file mode 100644 index 0000000..ffab4e3 --- /dev/null +++ b/tests/AuthContextQueueListenerTest.php @@ -0,0 +1,124 @@ +id(); + $table->string('name'); + $table->string('email'); + }); + + // Register test routes + Route::middleware('api')->group(function () { + Route::post('/test/emit-event', [ + TestController::class, + 'emitEvent', + ]); + }); + + Event::subscribe(TestEventSubscriber::class); +}); + +it('preserves auth context when Listener is dispatched', function () { + Queue::fake()->serializeAndRestore(); + + /** @var \Mockery\Mock $loggerSpy */ + $loggerSpy = Mockery::spy('logger'); + $this->app->instance('log', $loggerSpy); + + // Arrange + $user = User::create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + // Act + $response = $this->actingAs($user)->postJson('/test/emit-event'); + + // Assert + $response->assertSuccessful(); + + Queue::assertCount(1); + + Queue::assertPushed(CallQueuedListener::class, function (CallQueuedListener $job) use ($user) { + return collect($job->middleware)->filter(function ($middleware) use ($user) { + return get_class($middleware) === RestoreAuthenticatedContextMiddleware::class && + $middleware->getAuthUser()->getAuthIdentifier() === $user->getKey(); + }); + }); +}); + +it('preserves auth context when Listener is executed', function () { + Queue::setDefaultDriver('database'); + + /** @var \Mockery\Mock $loggerSpy */ + $loggerSpy = Mockery::spy('logger'); + $this->app->instance('log', $loggerSpy); + + // Arrange + $user = User::create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + // Act + $response = $this->actingAs($user)->postJson('/test/emit-event'); + + // Assert + $response->assertSuccessful(); + + expect(DB::table('jobs')->count())->toBe(1); + + # Reset Auth to prevent reuse auth data of the above API + auth()->guard()->forgetUser(); + + $this->artisan('queue:work --once'); + + // Assert logger was called with correct values + $loggerSpy->shouldHaveReceived('info') + ->with("Auth ID: {$user->id}") + ->once(); + + $loggerSpy->shouldHaveReceived('info') + ->with('Auth Check: 1') + ->once(); +}); + +it('handles unauthenticated requests correctly', function () { + // Arrange + Queue::fake()->serializeAndRestore(); + + // Arrange + User::create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + // Act + $response = $this->postJson('/test/emit-event'); + + // Assert + $response->assertSuccessful(); + + Queue::assertPushed(CallQueuedListener::class, function (CallQueuedListener $job) { + return collect($job->middleware)->filter(function ($middleware) { + return get_class($middleware) === RestoreAuthenticatedContextMiddleware::class && + empty($middleware->getAuthUser()); + }); + }); +}); + +afterEach(function () { + Schema::dropIfExists('users'); + DB::table('jobs')->delete(); +}); diff --git a/tests/AuthContextQueueNotificationTest.php b/tests/AuthContextQueueNotificationTest.php new file mode 100644 index 0000000..b85625b --- /dev/null +++ b/tests/AuthContextQueueNotificationTest.php @@ -0,0 +1,114 @@ +id(); + $table->string('name'); + $table->string('email'); + }); + + // Register test routes + Route::middleware('api')->group(function () { + Route::post('/test/send-notification', [ + TestController::class, + 'sendNotification', + ]); + }); +}); + +it('preserves auth context when Notification is dispatched', function () { + Notification::fake()->serializeAndRestore(); + + /** @var \Mockery\Mock $loggerSpy */ + $loggerSpy = Mockery::spy('logger'); + $this->app->instance('log', $loggerSpy); + + // Arrange + $user = User::create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + // Act + $response = $this->actingAs($user)->postJson('/test/send-notification'); + + // Assert + $response->assertSuccessful(); + + Notification::assertCount(1); + + Notification::assertSentTo($user, TestNotification::class, function (TestNotification $job) use ($user) { + return collect($job->middleware)->filter(function ($middleware) use ($user) { + return get_class($middleware) === RestoreAuthenticatedContextMiddleware::class && + $middleware->getAuthUser()->getAuthIdentifier() === $user->getKey(); + }); + }); +}); + +it('preserves auth context when Notification is executed', function () { + Queue::setDefaultDriver('database'); + + /** @var \Mockery\Mock $loggerSpy */ + $loggerSpy = Mockery::spy('logger'); + $this->app->instance('log', $loggerSpy); + + // Arrange + $user = User::create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + // Act + $response = $this->actingAs($user)->postJson('/test/send-notification'); + + // Assert + $response->assertSuccessful(); + + # Reset Auth to prevent reuse auth data of the above API + auth()->guard()->forgetUser(); + + $this->artisan('queue:work --once'); + + expect(DB::table('notifications')->count())->toBe(1); + + expect(DB::table('notifications')->value('data'))->toBe("[{$user->getAuthIdentifier()}]"); +}); + +it('handles unauthenticated requests correctly', function () { + // Arrange + Notification::fake()->serializeAndRestore(); + + // Arrange + $user = User::create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + // Act + $response = $this->postJson('/test/send-notification'); + + // Assert + $response->assertSuccessful(); + + Notification::assertSentTo($user, TestNotification::class, function (TestNotification $job) { + return collect($job->middleware)->filter(function ($middleware) { + return get_class($middleware) === RestoreAuthenticatedContextMiddleware::class && + empty($middleware->getAuthUser()); + }); + }); +}); + +afterEach(function () { + Schema::dropIfExists('users'); + DB::table('jobs')->delete(); +}); diff --git a/tests/Controllers/TestController.php b/tests/Controllers/TestController.php new file mode 100644 index 0000000..0860731 --- /dev/null +++ b/tests/Controllers/TestController.php @@ -0,0 +1,38 @@ +json(['status' => 'dispatched job']); + } + + public function sendNotification(): JsonResponse + { + $notification = new TestNotification(); + User::query()->first()->notify($notification); + + return response()->json(['status' => 'dispatched notification']); + } + + public function emitEvent(): JsonResponse + { + User::query()->first()->update([ + 'name' => 'Name Updated', + ]); + + return response()->json(['status' => 'emitted event']); + } +} diff --git a/tests/ExampleTest.php b/tests/ExampleTest.php deleted file mode 100644 index 5d36321..0000000 --- a/tests/ExampleTest.php +++ /dev/null @@ -1,5 +0,0 @@ -toBeTrue(); -}); diff --git a/tests/Jobs/TestWasAuthenticatedJob.php b/tests/Jobs/TestWasAuthenticatedJob.php new file mode 100644 index 0000000..51ac38b --- /dev/null +++ b/tests/Jobs/TestWasAuthenticatedJob.php @@ -0,0 +1,20 @@ +info('Auth ID: '. auth()->id()); + logger()->info('Auth Check: '.auth()->check()); + } +} diff --git a/tests/Jobs/TestWasNotAuthenticatedJob.php b/tests/Jobs/TestWasNotAuthenticatedJob.php new file mode 100644 index 0000000..942381e --- /dev/null +++ b/tests/Jobs/TestWasNotAuthenticatedJob.php @@ -0,0 +1,20 @@ +info('Auth ID: '. auth()->id()); + logger()->info('Auth Check: '.auth()->check()); + } +} diff --git a/tests/Listeners/TestEventSubscriber.php b/tests/Listeners/TestEventSubscriber.php new file mode 100644 index 0000000..2efe60e --- /dev/null +++ b/tests/Listeners/TestEventSubscriber.php @@ -0,0 +1,25 @@ +listen('eloquent.updated: ' . User::class, [self::class, 'onUserUpdated']); + } + + public function onUserUpdated(User $user) + { + logger()->info('Auth ID: '. auth()->id()); + logger()->info('Auth Check: '.auth()->check()); + } +} diff --git a/tests/Models/User.php b/tests/Models/User.php new file mode 100644 index 0000000..fead25e --- /dev/null +++ b/tests/Models/User.php @@ -0,0 +1,17 @@ +id()]; + } +} diff --git a/tests/Pest.php b/tests/Pest.php index 7fe1500..2d06ab0 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,5 +1,5 @@ in(__DIR__); diff --git a/tests/TestCase.php b/tests/TestCase.php index 220551b..f6e9f59 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,11 +1,17 @@ 'VendorName\\Skeleton\\Database\\Factories\\'.class_basename($modelName).'Factory' + fn (string $modelName) => 'DatPM\\LaravelAuthQueue\\Database\\Factories\\'.class_basename($modelName).'Factory' ); } protected function getPackageProviders($app) { return [ - SkeletonServiceProvider::class, + LaravelAuthQueueServiceProvider::class, ]; } @@ -28,10 +34,37 @@ public function getEnvironmentSetUp($app) { config()->set('database.default', 'testing'); - /* - foreach (\Illuminate\Support\Facades\File::allFiles(__DIR__ . '/database/migrations') as $migration) { - (include $migration->getRealPath())->up(); - } - */ + // Set up queue configuration for testing + $app['config']->set('queue.default', 'database'); + $app['config']->set('queue.connections.database', [ + 'driver' => 'database', + 'table' => 'jobs', + 'queue' => 'default', + 'retry_after' => 90, + ]); + + // Make sure the jobs table exists + if (!Schema::hasTable('jobs')) { + Schema::create('jobs', function ($table) { + $table->bigIncrements('id'); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + } + + if (!Schema::hasTable('notifications')) { + Schema::create('notifications', function (Blueprint $table) { + $table->uuid('id')->primary(); + $table->string('type'); + $table->morphs('notifiable'); + $table->text('data'); + $table->timestamp('read_at')->nullable(); + $table->timestamps(); + }); + } } } From 6187b70fea3362bb4f3bdaf1a0a6109310d178b9 Mon Sep 17 00:00:00 2001 From: datpmwork <9279315+datpmwork@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:29:00 +0000 Subject: [PATCH 02/32] Fix styling --- src/LaravelAuthQueueServiceProvider.php | 12 +++++----- .../RestoreAuthenticatedContextMiddleware.php | 7 ++---- tests/AuthContextQueueJobTest.php | 22 +++++++++---------- tests/AuthContextQueueListenerTest.php | 22 +++++++++---------- tests/AuthContextQueueNotificationTest.php | 20 ++++++++--------- tests/Controllers/TestController.php | 10 ++++----- tests/Jobs/TestWasAuthenticatedJob.php | 8 +++---- tests/Jobs/TestWasNotAuthenticatedJob.php | 6 ++--- tests/Listeners/TestEventSubscriber.php | 10 ++++----- tests/Models/User.php | 4 ++-- tests/Notifications/TestNotification.php | 6 ++--- tests/TestCase.php | 12 +++++----- 12 files changed, 68 insertions(+), 71 deletions(-) diff --git a/src/LaravelAuthQueueServiceProvider.php b/src/LaravelAuthQueueServiceProvider.php index 7205667..5c56522 100644 --- a/src/LaravelAuthQueueServiceProvider.php +++ b/src/LaravelAuthQueueServiceProvider.php @@ -2,26 +2,26 @@ namespace DatPM\LaravelAuthQueue; +use DatPM\LaravelAuthQueue\Guards\KernelGuard; use Illuminate\Support\Facades\Auth; use Spatie\LaravelPackageTools\Package; -use DatPM\LaravelAuthQueue\Guards\KernelGuard; use Spatie\LaravelPackageTools\PackageServiceProvider; class LaravelAuthQueueServiceProvider extends PackageServiceProvider { public function boot() { - # Skip booting in non-console mode - if (!$this->app->runningInConsole()) { + // Skip booting in non-console mode + if (! $this->app->runningInConsole()) { return; } - # Register new AuthGuard for Kernel Application + // Register new AuthGuard for Kernel Application Auth::extend('kernel', function () { - return new KernelGuard(); + return new KernelGuard; }); - # Add a new KernelGuard to support authenticated in CLI + // Add a new KernelGuard to support authenticated in CLI $defaultGuard = config('auth.defaults.guard'); config(['auth.guards.kernel' => [ diff --git a/src/Middlewares/RestoreAuthenticatedContextMiddleware.php b/src/Middlewares/RestoreAuthenticatedContextMiddleware.php index e28aa4e..f461258 100644 --- a/src/Middlewares/RestoreAuthenticatedContextMiddleware.php +++ b/src/Middlewares/RestoreAuthenticatedContextMiddleware.php @@ -2,14 +2,11 @@ namespace DatPM\LaravelAuthQueue\Middlewares; -use Illuminate\Support\Facades\Auth; use Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Support\Facades\Auth; class RestoreAuthenticatedContextMiddleware { - /** - * @var - */ protected $authUser; public function __construct($authUser) @@ -23,7 +20,7 @@ public function handle($command, callable $next) $guard = auth(); - if (!empty($this->authUser)) { + if (! empty($this->authUser)) { $guard->setUser($this->authUser); } diff --git a/tests/AuthContextQueueJobTest.php b/tests/AuthContextQueueJobTest.php index be30462..2d0fb97 100644 --- a/tests/AuthContextQueueJobTest.php +++ b/tests/AuthContextQueueJobTest.php @@ -1,14 +1,14 @@ 'Test User', + 'name' => 'Test User', 'email' => 'test@example.com', ]); @@ -65,7 +65,7 @@ // Arrange $user = User::create([ - 'name' => 'Test User', + 'name' => 'Test User', 'email' => 'test@example.com', ]); @@ -77,7 +77,7 @@ expect(DB::table('jobs')->count())->toBe(2); - # Reset Auth to prevent reuse auth data of the above API + // Reset Auth to prevent reuse auth data of the above API auth()->guard()->forgetUser(); $this->artisan('queue:work --once'); @@ -88,14 +88,14 @@ ->once(); $loggerSpy->shouldHaveReceived('info') - ->with("Auth Check: 1") + ->with('Auth Check: 1') ->once(); $this->artisan('queue:work --once'); // Assert logger was called with correct values $loggerSpy->shouldHaveReceived('info') - ->with("Auth ID: ") + ->with('Auth ID: ') ->once(); $loggerSpy->shouldHaveReceived('info') diff --git a/tests/AuthContextQueueListenerTest.php b/tests/AuthContextQueueListenerTest.php index ffab4e3..4cbb4b5 100644 --- a/tests/AuthContextQueueListenerTest.php +++ b/tests/AuthContextQueueListenerTest.php @@ -1,15 +1,15 @@ 'Test User', + 'name' => 'Test User', 'email' => 'test@example.com', ]); @@ -67,7 +67,7 @@ // Arrange $user = User::create([ - 'name' => 'Test User', + 'name' => 'Test User', 'email' => 'test@example.com', ]); @@ -79,7 +79,7 @@ expect(DB::table('jobs')->count())->toBe(1); - # Reset Auth to prevent reuse auth data of the above API + // Reset Auth to prevent reuse auth data of the above API auth()->guard()->forgetUser(); $this->artisan('queue:work --once'); @@ -100,7 +100,7 @@ // Arrange User::create([ - 'name' => 'Test User', + 'name' => 'Test User', 'email' => 'test@example.com', ]); diff --git a/tests/AuthContextQueueNotificationTest.php b/tests/AuthContextQueueNotificationTest.php index b85625b..d0a9331 100644 --- a/tests/AuthContextQueueNotificationTest.php +++ b/tests/AuthContextQueueNotificationTest.php @@ -1,14 +1,14 @@ 'Test User', + 'name' => 'Test User', 'email' => 'test@example.com', ]); @@ -64,7 +64,7 @@ // Arrange $user = User::create([ - 'name' => 'Test User', + 'name' => 'Test User', 'email' => 'test@example.com', ]); @@ -74,7 +74,7 @@ // Assert $response->assertSuccessful(); - # Reset Auth to prevent reuse auth data of the above API + // Reset Auth to prevent reuse auth data of the above API auth()->guard()->forgetUser(); $this->artisan('queue:work --once'); @@ -90,7 +90,7 @@ // Arrange $user = User::create([ - 'name' => 'Test User', + 'name' => 'Test User', 'email' => 'test@example.com', ]); diff --git a/tests/Controllers/TestController.php b/tests/Controllers/TestController.php index 0860731..738115c 100644 --- a/tests/Controllers/TestController.php +++ b/tests/Controllers/TestController.php @@ -2,12 +2,12 @@ namespace DatPM\LaravelAuthQueue\Tests\Controllers; -use Illuminate\Http\JsonResponse; -use Illuminate\Routing\Controller; -use DatPM\LaravelAuthQueue\Tests\Models\User; use DatPM\LaravelAuthQueue\Tests\Jobs\TestWasAuthenticatedJob; -use DatPM\LaravelAuthQueue\Tests\Notifications\TestNotification; use DatPM\LaravelAuthQueue\Tests\Jobs\TestWasNotAuthenticatedJob; +use DatPM\LaravelAuthQueue\Tests\Models\User; +use DatPM\LaravelAuthQueue\Tests\Notifications\TestNotification; +use Illuminate\Http\JsonResponse; +use Illuminate\Routing\Controller; class TestController extends Controller { @@ -21,7 +21,7 @@ public function dispatchJob(): JsonResponse public function sendNotification(): JsonResponse { - $notification = new TestNotification(); + $notification = new TestNotification; User::query()->first()->notify($notification); return response()->json(['status' => 'dispatched notification']); diff --git a/tests/Jobs/TestWasAuthenticatedJob.php b/tests/Jobs/TestWasAuthenticatedJob.php index 51ac38b..1b483b0 100644 --- a/tests/Jobs/TestWasAuthenticatedJob.php +++ b/tests/Jobs/TestWasAuthenticatedJob.php @@ -2,11 +2,11 @@ namespace DatPM\LaravelAuthQueue\Tests\Jobs; +use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; use Illuminate\Bus\Queueable; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Contracts\Queue\ShouldQueue; -use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; +use Illuminate\Foundation\Bus\Dispatchable; +use Illuminate\Queue\InteractsWithQueue; class TestWasAuthenticatedJob implements ShouldQueue { @@ -14,7 +14,7 @@ class TestWasAuthenticatedJob implements ShouldQueue public function handle() { - logger()->info('Auth ID: '. auth()->id()); + logger()->info('Auth ID: '.auth()->id()); logger()->info('Auth Check: '.auth()->check()); } } diff --git a/tests/Jobs/TestWasNotAuthenticatedJob.php b/tests/Jobs/TestWasNotAuthenticatedJob.php index 942381e..d5f6a3f 100644 --- a/tests/Jobs/TestWasNotAuthenticatedJob.php +++ b/tests/Jobs/TestWasNotAuthenticatedJob.php @@ -3,10 +3,10 @@ namespace DatPM\LaravelAuthQueue\Tests\Jobs; use Illuminate\Bus\Queueable; -use Illuminate\Queue\SerializesModels; -use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; +use Illuminate\Queue\InteractsWithQueue; +use Illuminate\Queue\SerializesModels; class TestWasNotAuthenticatedJob implements ShouldQueue { @@ -14,7 +14,7 @@ class TestWasNotAuthenticatedJob implements ShouldQueue public function handle(): void { - logger()->info('Auth ID: '. auth()->id()); + logger()->info('Auth ID: '.auth()->id()); logger()->info('Auth Check: '.auth()->check()); } } diff --git a/tests/Listeners/TestEventSubscriber.php b/tests/Listeners/TestEventSubscriber.php index 2efe60e..4b6e157 100644 --- a/tests/Listeners/TestEventSubscriber.php +++ b/tests/Listeners/TestEventSubscriber.php @@ -2,11 +2,11 @@ namespace DatPM\LaravelAuthQueue\Tests\Listeners; -use Illuminate\Bus\Queueable; -use Illuminate\Events\Dispatcher; -use Illuminate\Contracts\Queue\ShouldQueue; use DatPM\LaravelAuthQueue\Tests\Models\User; use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Events\Dispatcher; class TestEventSubscriber implements ShouldQueue { @@ -14,12 +14,12 @@ class TestEventSubscriber implements ShouldQueue public function subscribe(Dispatcher $dispatcher) { - $dispatcher->listen('eloquent.updated: ' . User::class, [self::class, 'onUserUpdated']); + $dispatcher->listen('eloquent.updated: '.User::class, [self::class, 'onUserUpdated']); } public function onUserUpdated(User $user) { - logger()->info('Auth ID: '. auth()->id()); + logger()->info('Auth ID: '.auth()->id()); logger()->info('Auth Check: '.auth()->check()); } } diff --git a/tests/Models/User.php b/tests/Models/User.php index fead25e..bd864ff 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -2,9 +2,9 @@ namespace DatPM\LaravelAuthQueue\Tests\Models; -use Illuminate\Notifications\Notifiable; -use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Foundation\Auth\User as Authenticatable; +use Illuminate\Notifications\Notifiable; use Spatie\LaravelPackageTools\Concerns\Package\HasRoutes; class User extends Authenticatable diff --git a/tests/Notifications/TestNotification.php b/tests/Notifications/TestNotification.php index f2ce454..662332f 100644 --- a/tests/Notifications/TestNotification.php +++ b/tests/Notifications/TestNotification.php @@ -2,10 +2,10 @@ namespace DatPM\LaravelAuthQueue\Tests\Notifications; -use Illuminate\Notifications\Notification; -use Illuminate\Foundation\Queue\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Foundation\Queue\Queueable; +use Illuminate\Notifications\Notification; class TestNotification extends Notification implements ShouldQueue { diff --git a/tests/TestCase.php b/tests/TestCase.php index f6e9f59..42dd4b5 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,12 +2,12 @@ namespace DatPM\LaravelAuthQueue\Tests; -use Illuminate\Support\Facades\Schema; -use Illuminate\Database\Schema\Blueprint; -use Orchestra\Testbench\TestCase as Orchestra; +use DatPM\LaravelAuthQueue\LaravelAuthQueueServiceProvider; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Database\Eloquent\Factories\Factory; -use DatPM\LaravelAuthQueue\LaravelAuthQueueServiceProvider; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; +use Orchestra\Testbench\TestCase as Orchestra; /** * @method \Illuminate\Foundation\Testing\TestCase actingAs(Authenticatable $user, string|null $guard = null) @@ -44,7 +44,7 @@ public function getEnvironmentSetUp($app) ]); // Make sure the jobs table exists - if (!Schema::hasTable('jobs')) { + if (! Schema::hasTable('jobs')) { Schema::create('jobs', function ($table) { $table->bigIncrements('id'); $table->string('queue')->index(); @@ -56,7 +56,7 @@ public function getEnvironmentSetUp($app) }); } - if (!Schema::hasTable('notifications')) { + if (! Schema::hasTable('notifications')) { Schema::create('notifications', function (Blueprint $table) { $table->uuid('id')->primary(); $table->string('type'); From 715e9a77a82818da6a50472d7f7a90e35ba71075 Mon Sep 17 00:00:00 2001 From: DatPM Date: Wed, 2 Jul 2025 23:33:28 +0700 Subject: [PATCH 03/32] Updates support for PHP and Laravel versions Removes support for older PHP and Laravel versions and updates the test matrix accordingly. This ensures compatibility with actively maintained versions and simplifies the testing process. --- .github/workflows/run-tests.yml | 10 +++------- README.md | 5 +++++ composer.json | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 2f4c7ec..e25ce8d 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -8,16 +8,12 @@ jobs: strategy: fail-fast: false matrix: - php: [8.1, 8.2, 8.3] - laravel: [9.*, 10.*, 11.*, 12.*] + php: [8.2, 8.3] + laravel: [10.*, 11.*, 12.*] stability: [prefer-lowest, prefer-stable] exclude: - - laravel: 9.* - php: 8.3 - laravel: 12.* - php: 8.1 - - laravel: 11.* - php: 8.1 + php: 8.2 name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} diff --git a/README.md b/README.md index 6902dab..aae0c5c 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,11 @@ auth() manager when the job is being handled. This is particularly useful when you need to maintain user context across asynchronous operations. +## Requirements + +- PHP ^8.2 +- Laravel 10.x|11.x|12.x + ## Support us You can support this project via [GitHub Sponsors](https://github.com/sponsors/datpmwork). diff --git a/composer.json b/composer.json index 845625f..8a85bbd 100644 --- a/composer.json +++ b/composer.json @@ -16,14 +16,14 @@ } ], "require": { - "php": "^8.1", - "illuminate/support": "^9.0|^10.0|^11.0|^12.0" + "php": "^8.2", + "illuminate/support": "^10.0|^11.0|^12.0" }, "require-dev": { "laravel/pint": "^1.14", "nunomaduro/collision": "^8.1.1||^7.10.0", "larastan/larastan": "^2.9||^3.0", - "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", + "orchestra/testbench": "^8.0|^9.0|^10.0", "pestphp/pest": "^3.0", "pestphp/pest-plugin-arch": "^3.0", "pestphp/pest-plugin-laravel": "^3.0", From a0571ff86f062f86a076d1c766e8e339f7746a84 Mon Sep 17 00:00:00 2001 From: DatPM Date: Wed, 2 Jul 2025 23:36:00 +0700 Subject: [PATCH 04/32] Refactors service provider implementation. Updates the service provider to extend the base Laravel ServiceProvider instead of spatie/laravel-package-tools. Removes package configuration. --- src/LaravelAuthQueueServiceProvider.php | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/LaravelAuthQueueServiceProvider.php b/src/LaravelAuthQueueServiceProvider.php index 7205667..81b6d28 100644 --- a/src/LaravelAuthQueueServiceProvider.php +++ b/src/LaravelAuthQueueServiceProvider.php @@ -3,11 +3,10 @@ namespace DatPM\LaravelAuthQueue; use Illuminate\Support\Facades\Auth; -use Spatie\LaravelPackageTools\Package; +use Illuminate\Support\ServiceProvider; use DatPM\LaravelAuthQueue\Guards\KernelGuard; -use Spatie\LaravelPackageTools\PackageServiceProvider; -class LaravelAuthQueueServiceProvider extends PackageServiceProvider +class LaravelAuthQueueServiceProvider extends ServiceProvider { public function boot() { @@ -29,14 +28,4 @@ public function boot() 'provider' => config("auth.guards.{$defaultGuard}.provider"), ]]); } - - public function configurePackage(Package $package): void - { - /* - * This class is a Package Service Provider - * - * More info: https://github.com/spatie/laravel-package-tools - */ - $package->name('laravel-queueable-auth-context'); - } } From eef68bd767f7ee3e5aa97f507c3166bdf9ef1fb2 Mon Sep 17 00:00:00 2001 From: datpmwork <9279315+datpmwork@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:37:50 +0000 Subject: [PATCH 05/32] Fix styling --- src/LaravelAuthQueueServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LaravelAuthQueueServiceProvider.php b/src/LaravelAuthQueueServiceProvider.php index 1422f9b..032f784 100644 --- a/src/LaravelAuthQueueServiceProvider.php +++ b/src/LaravelAuthQueueServiceProvider.php @@ -2,9 +2,9 @@ namespace DatPM\LaravelAuthQueue; +use DatPM\LaravelAuthQueue\Guards\KernelGuard; use Illuminate\Support\Facades\Auth; use Illuminate\Support\ServiceProvider; -use DatPM\LaravelAuthQueue\Guards\KernelGuard; class LaravelAuthQueueServiceProvider extends ServiceProvider { From 103b13e752f94cee92635eb62ea9939f4878b8e5 Mon Sep 17 00:00:00 2001 From: DatPM Date: Wed, 2 Jul 2025 23:39:25 +0700 Subject: [PATCH 06/32] Updates development dependencies Updates development dependencies in composer.json to more specific and/or newer compatible versions. This ensures better stability and compatibility within the development environment. --- composer.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 8a85bbd..595d08d 100644 --- a/composer.json +++ b/composer.json @@ -21,15 +21,15 @@ }, "require-dev": { "laravel/pint": "^1.14", - "nunomaduro/collision": "^8.1.1||^7.10.0", - "larastan/larastan": "^2.9||^3.0", - "orchestra/testbench": "^8.0|^9.0|^10.0", - "pestphp/pest": "^3.0", - "pestphp/pest-plugin-arch": "^3.0", - "pestphp/pest-plugin-laravel": "^3.0", - "phpstan/extension-installer": "^1.3||^2.0", - "phpstan/phpstan-deprecation-rules": "^1.1||^2.0", - "phpstan/phpstan-phpunit": "^1.3||^2.0" + "nunomaduro/collision": "^7.10.0", + "larastan/larastan": "^2.9", + "orchestra/testbench": "^8.0", + "pestphp/pest": "^2.24", + "pestphp/pest-plugin-arch": "^2.0", + "pestphp/pest-plugin-laravel": "^2.0", + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan-deprecation-rules": "^1.1", + "phpstan/phpstan-phpunit": "^1.3" }, "autoload": { "psr-4": { From fed9a1be04e74863f55fa06ac38d2858ffdda0e5 Mon Sep 17 00:00:00 2001 From: DatPM Date: Wed, 2 Jul 2025 23:40:16 +0700 Subject: [PATCH 07/32] Removes HasRoutes trait from User model. The HasRoutes trait was part of a package and is no longer needed in the User model after refactoring. This change removes the trait. --- tests/Models/User.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/Models/User.php b/tests/Models/User.php index bd864ff..b550c25 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -2,14 +2,13 @@ namespace DatPM\LaravelAuthQueue\Tests\Models; +use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; -use Illuminate\Notifications\Notifiable; -use Spatie\LaravelPackageTools\Concerns\Package\HasRoutes; class User extends Authenticatable { - use HasFactory, HasRoutes, Notifiable; + use HasFactory, Notifiable; protected $fillable = ['name', 'email']; From e3b57e0d4177617eabcf7915cb5766bde0a1ff15 Mon Sep 17 00:00:00 2001 From: datpmwork <9279315+datpmwork@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:40:41 +0000 Subject: [PATCH 08/32] Fix styling --- tests/Models/User.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Models/User.php b/tests/Models/User.php index b550c25..d0a2eef 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -2,9 +2,9 @@ namespace DatPM\LaravelAuthQueue\Tests\Models; -use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; +use Illuminate\Notifications\Notifiable; class User extends Authenticatable { From 720e19f418a5d97911b04bf7a02aacd600f21c30 Mon Sep 17 00:00:00 2001 From: DatPM Date: Wed, 2 Jul 2025 23:42:30 +0700 Subject: [PATCH 09/32] Updates testbench dependency Extends the allowed versions of the testbench dependency. This change broadens compatibility with newer Laravel versions, allowing the package to be used in projects running Laravel 9 and 10, in addition to Laravel 8. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 595d08d..b8a77ab 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "laravel/pint": "^1.14", "nunomaduro/collision": "^7.10.0", "larastan/larastan": "^2.9", - "orchestra/testbench": "^8.0", + "orchestra/testbench": "^8.0|^9.0|^10.0", "pestphp/pest": "^2.24", "pestphp/pest-plugin-arch": "^2.0", "pestphp/pest-plugin-laravel": "^2.0", From dd6c9a529e748c654e8df6c7480dd46e65beecbf Mon Sep 17 00:00:00 2001 From: DatPM Date: Wed, 2 Jul 2025 23:47:08 +0700 Subject: [PATCH 10/32] Fix Wrong Trait --- .github/workflows/run-tests.yml | 2 +- tests/Notifications/TestNotification.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index e25ce8d..bff26ab 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -10,7 +10,7 @@ jobs: matrix: php: [8.2, 8.3] laravel: [10.*, 11.*, 12.*] - stability: [prefer-lowest, prefer-stable] + stability: [prefer-stable] exclude: - laravel: 12.* php: 8.2 diff --git a/tests/Notifications/TestNotification.php b/tests/Notifications/TestNotification.php index 662332f..0c7e532 100644 --- a/tests/Notifications/TestNotification.php +++ b/tests/Notifications/TestNotification.php @@ -2,10 +2,10 @@ namespace DatPM\LaravelAuthQueue\Tests\Notifications; -use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; -use Illuminate\Contracts\Queue\ShouldQueue; -use Illuminate\Foundation\Queue\Queueable; +use Illuminate\Bus\Queueable; use Illuminate\Notifications\Notification; +use Illuminate\Contracts\Queue\ShouldQueue; +use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; class TestNotification extends Notification implements ShouldQueue { From 01ed22a741130ab96a29d9abc84d5bcf82a7c750 Mon Sep 17 00:00:00 2001 From: datpmwork <9279315+datpmwork@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:47:29 +0000 Subject: [PATCH 11/32] Fix styling --- tests/Notifications/TestNotification.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Notifications/TestNotification.php b/tests/Notifications/TestNotification.php index 0c7e532..9dfa5c6 100644 --- a/tests/Notifications/TestNotification.php +++ b/tests/Notifications/TestNotification.php @@ -2,10 +2,10 @@ namespace DatPM\LaravelAuthQueue\Tests\Notifications; +use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; use Illuminate\Bus\Queueable; -use Illuminate\Notifications\Notification; use Illuminate\Contracts\Queue\ShouldQueue; -use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; +use Illuminate\Notifications\Notification; class TestNotification extends Notification implements ShouldQueue { From 580657d6f16ef27b51702f35c9213c1003c7efaf Mon Sep 17 00:00:00 2001 From: DatPM Date: Wed, 2 Jul 2025 23:50:21 +0700 Subject: [PATCH 12/32] Update Deps --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b8a77ab..574328b 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ }, "require-dev": { "laravel/pint": "^1.14", - "nunomaduro/collision": "^7.10.0", + "nunomaduro/collision": "^7.0|^8.0", "larastan/larastan": "^2.9", "orchestra/testbench": "^8.0|^9.0|^10.0", "pestphp/pest": "^2.24", From 93d9279ea31e275a7ec4c1f41a317eecd75e957d Mon Sep 17 00:00:00 2001 From: DatPM Date: Wed, 2 Jul 2025 23:52:51 +0700 Subject: [PATCH 13/32] Update Deps --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 574328b..662f737 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "nunomaduro/collision": "^7.0|^8.0", "larastan/larastan": "^2.9", "orchestra/testbench": "^8.0|^9.0|^10.0", - "pestphp/pest": "^2.24", + "pestphp/pest": "^2.24|^3.0", "pestphp/pest-plugin-arch": "^2.0", "pestphp/pest-plugin-laravel": "^2.0", "phpstan/extension-installer": "^1.3", From c355c7f4ae1de0f1ad47d507a3363bf4413ac1b2 Mon Sep 17 00:00:00 2001 From: DatPM Date: Wed, 2 Jul 2025 23:54:15 +0700 Subject: [PATCH 14/32] Update Deps --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 662f737..8a4f021 100644 --- a/composer.json +++ b/composer.json @@ -24,9 +24,9 @@ "nunomaduro/collision": "^7.0|^8.0", "larastan/larastan": "^2.9", "orchestra/testbench": "^8.0|^9.0|^10.0", - "pestphp/pest": "^2.24|^3.0", - "pestphp/pest-plugin-arch": "^2.0", - "pestphp/pest-plugin-laravel": "^2.0", + "pestphp/pest": "^2.0|^3.0", + "pestphp/pest-plugin-arch": "^2.0|^3.0", + "pestphp/pest-plugin-laravel": "^2.0|^3.0", "phpstan/extension-installer": "^1.3", "phpstan/phpstan-deprecation-rules": "^1.1", "phpstan/phpstan-phpunit": "^1.3" From 4ad6a0e07288f8d867856b40809634f1a6017010 Mon Sep 17 00:00:00 2001 From: DatPM Date: Wed, 2 Jul 2025 23:55:39 +0700 Subject: [PATCH 15/32] Update Deps --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8a4f021..377b77c 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "require-dev": { "laravel/pint": "^1.14", "nunomaduro/collision": "^7.0|^8.0", - "larastan/larastan": "^2.9", + "larastan/larastan": "^2.9|^3.0", "orchestra/testbench": "^8.0|^9.0|^10.0", "pestphp/pest": "^2.0|^3.0", "pestphp/pest-plugin-arch": "^2.0|^3.0", From aadbe41e16513da40e6b86d7bcaa08981d9357b5 Mon Sep 17 00:00:00 2001 From: DatPM Date: Thu, 3 Jul 2025 07:38:37 +0700 Subject: [PATCH 16/32] Removes static analysis tooling Removes static analysis tooling dependencies and configuration. This simplifies the development environment and reduces the number of dependencies. --- composer.json | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 377b77c..a9f8a37 100644 --- a/composer.json +++ b/composer.json @@ -22,14 +22,10 @@ "require-dev": { "laravel/pint": "^1.14", "nunomaduro/collision": "^7.0|^8.0", - "larastan/larastan": "^2.9|^3.0", "orchestra/testbench": "^8.0|^9.0|^10.0", "pestphp/pest": "^2.0|^3.0", "pestphp/pest-plugin-arch": "^2.0|^3.0", - "pestphp/pest-plugin-laravel": "^2.0|^3.0", - "phpstan/extension-installer": "^1.3", - "phpstan/phpstan-deprecation-rules": "^1.1", - "phpstan/phpstan-phpunit": "^1.3" + "pestphp/pest-plugin-laravel": "^2.0|^3.0" }, "autoload": { "psr-4": { @@ -44,7 +40,6 @@ "scripts": { "post-autoload-dump": "@composer run prepare", "prepare": "@php vendor/bin/testbench package:discover --ansi", - "analyse": "vendor/bin/phpstan analyse", "test": "vendor/bin/pest", "test-coverage": "vendor/bin/pest --coverage", "format": "vendor/bin/pint" @@ -52,8 +47,7 @@ "config": { "sort-packages": true, "allow-plugins": { - "pestphp/pest-plugin": true, - "phpstan/extension-installer": true + "pestphp/pest-plugin": true } }, "extra": { From 8de925b9fcabc6eedf07a4cadf0f550971047ec4 Mon Sep 17 00:00:00 2001 From: DatPM Date: Thu, 3 Jul 2025 18:41:11 +0700 Subject: [PATCH 17/32] Extends compatibility and adds static analysis Enhances compatibility by relaxing PHP and Laravel version constraints. Adds static analysis tools for improved code quality and reliability. Removes minimum stability constraint. --- .github/workflows/run-tests.yml | 14 +++++++++++--- composer.json | 14 ++++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index bff26ab..8f20c49 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -8,12 +8,20 @@ jobs: strategy: fail-fast: false matrix: - php: [8.2, 8.3] - laravel: [10.*, 11.*, 12.*] + php: [8.0, 8.1, 8.2, 8.3] + laravel: [9.*, 10.*, 11.*, 12.*] stability: [prefer-stable] exclude: + # Laravel 11 requires PHP 8.2+ + - laravel: 11.* + php: 8.0 + - laravel: 11.* + php: 8.1 + # Laravel 12 requires PHP 8.2+ - laravel: 12.* - php: 8.2 + php: 8.0 + - laravel: 12.* + php: 8.1 name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} diff --git a/composer.json b/composer.json index a9f8a37..c1c3bd5 100644 --- a/composer.json +++ b/composer.json @@ -16,16 +16,20 @@ } ], "require": { - "php": "^8.2", + "php": "^7.4|^8.0", "illuminate/support": "^10.0|^11.0|^12.0" }, "require-dev": { "laravel/pint": "^1.14", "nunomaduro/collision": "^7.0|^8.0", + "larastan/larastan": "^2.9|^3.1", "orchestra/testbench": "^8.0|^9.0|^10.0", "pestphp/pest": "^2.0|^3.0", "pestphp/pest-plugin-arch": "^2.0|^3.0", - "pestphp/pest-plugin-laravel": "^2.0|^3.0" + "pestphp/pest-plugin-laravel": "^2.0|^3.0", + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan-deprecation-rules": "^1.1|^2.0", + "phpstan/phpstan-phpunit": "^1.3|^2.0" }, "autoload": { "psr-4": { @@ -40,6 +44,7 @@ "scripts": { "post-autoload-dump": "@composer run prepare", "prepare": "@php vendor/bin/testbench package:discover --ansi", + "analyse": "vendor/bin/phpstan analyse", "test": "vendor/bin/pest", "test-coverage": "vendor/bin/pest --coverage", "format": "vendor/bin/pint" @@ -47,7 +52,8 @@ "config": { "sort-packages": true, "allow-plugins": { - "pestphp/pest-plugin": true + "pestphp/pest-plugin": true, + "phpstan/extension-installer": true } }, "extra": { @@ -57,6 +63,6 @@ ] } }, - "minimum-stability": "dev", + "minimum-stability": "stable", "prefer-stable": true } From 804720d9bd90da3aca3a8c70a5595560b16c92a3 Mon Sep 17 00:00:00 2001 From: DatPM Date: Thu, 3 Jul 2025 18:44:52 +0700 Subject: [PATCH 18/32] Allow L9 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c1c3bd5..99d7468 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.4|^8.0", - "illuminate/support": "^10.0|^11.0|^12.0" + "illuminate/support": "^9.0|^10.0|^11.0|^12.0" }, "require-dev": { "laravel/pint": "^1.14", From f6138516368d940528101c5566dbcae8f4b4acbc Mon Sep 17 00:00:00 2001 From: DatPM Date: Thu, 3 Jul 2025 18:47:33 +0700 Subject: [PATCH 19/32] Update Deps --- .github/workflows/run-tests.yml | 3 +++ composer.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 8f20c49..d4c6b33 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -13,6 +13,9 @@ jobs: stability: [prefer-stable] exclude: # Laravel 11 requires PHP 8.2+ + - laravel: 10.* + php: 8.0 + # Laravel 11 requires PHP 8.2+ - laravel: 11.* php: 8.0 - laravel: 11.* diff --git a/composer.json b/composer.json index 99d7468..eaf9639 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "illuminate/support": "^9.0|^10.0|^11.0|^12.0" }, "require-dev": { - "laravel/pint": "^1.14", + "laravel/pint": "^1.0", "nunomaduro/collision": "^7.0|^8.0", "larastan/larastan": "^2.9|^3.1", "orchestra/testbench": "^8.0|^9.0|^10.0", From 909e9fd9d6aeb49afd7cae2b8d9ac85141ec9432 Mon Sep 17 00:00:00 2001 From: DatPM Date: Thu, 3 Jul 2025 18:55:33 +0700 Subject: [PATCH 20/32] Update Deps --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index eaf9639..4fda1b4 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ }, "require-dev": { "laravel/pint": "^1.0", - "nunomaduro/collision": "^7.0|^8.0", + "nunomaduro/collision": "^6.0|^7.0|^8.0", "larastan/larastan": "^2.9|^3.1", "orchestra/testbench": "^8.0|^9.0|^10.0", "pestphp/pest": "^2.0|^3.0", From 868c4258fa13c62e1946c75182d437a2c117a9e3 Mon Sep 17 00:00:00 2001 From: DatPM Date: Thu, 3 Jul 2025 18:57:42 +0700 Subject: [PATCH 21/32] Update Desp --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4fda1b4..ecdbbce 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "laravel/pint": "^1.0", "nunomaduro/collision": "^6.0|^7.0|^8.0", "larastan/larastan": "^2.9|^3.1", - "orchestra/testbench": "^8.0|^9.0|^10.0", + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", "pestphp/pest": "^2.0|^3.0", "pestphp/pest-plugin-arch": "^2.0|^3.0", "pestphp/pest-plugin-laravel": "^2.0|^3.0", From 9fa8984842c4bdacaefc015e577e1387459dd168 Mon Sep 17 00:00:00 2001 From: DatPM Date: Thu, 3 Jul 2025 18:59:23 +0700 Subject: [PATCH 22/32] Update Deps --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ecdbbce..ddc2ebf 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "nunomaduro/collision": "^6.0|^7.0|^8.0", "larastan/larastan": "^2.9|^3.1", "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", - "pestphp/pest": "^2.0|^3.0", + "pestphp/pest": "^1.0|^2.0|^3.0", "pestphp/pest-plugin-arch": "^2.0|^3.0", "pestphp/pest-plugin-laravel": "^2.0|^3.0", "phpstan/extension-installer": "^1.3", From 935810051000e025590f499679b8abc52a186452 Mon Sep 17 00:00:00 2001 From: DatPM Date: Thu, 3 Jul 2025 19:00:08 +0700 Subject: [PATCH 23/32] Update Deps --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index ddc2ebf..0440334 100644 --- a/composer.json +++ b/composer.json @@ -25,8 +25,8 @@ "larastan/larastan": "^2.9|^3.1", "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", "pestphp/pest": "^1.0|^2.0|^3.0", - "pestphp/pest-plugin-arch": "^2.0|^3.0", - "pestphp/pest-plugin-laravel": "^2.0|^3.0", + "pestphp/pest-plugin-arch": "^1.0|^2.0|^3.0", + "pestphp/pest-plugin-laravel": "^1.0|^2.0|^3.0", "phpstan/extension-installer": "^1.3", "phpstan/phpstan-deprecation-rules": "^1.1|^2.0", "phpstan/phpstan-phpunit": "^1.3|^2.0" From 631b9140ac57c62eb1366517a18882052fd76ef9 Mon Sep 17 00:00:00 2001 From: DatPM Date: Thu, 3 Jul 2025 19:01:45 +0700 Subject: [PATCH 24/32] Update Deps --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0440334..01b8e81 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "require-dev": { "laravel/pint": "^1.0", "nunomaduro/collision": "^6.0|^7.0|^8.0", - "larastan/larastan": "^2.9|^3.1", + "larastan/larastan": "^1.0|^2.9|^3.1", "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", "pestphp/pest": "^1.0|^2.0|^3.0", "pestphp/pest-plugin-arch": "^1.0|^2.0|^3.0", From 5de8496a2df009349796304fd1a2702689e995ce Mon Sep 17 00:00:00 2001 From: DatPM Date: Fri, 4 Jul 2025 08:42:28 +0700 Subject: [PATCH 25/32] Update Test Case --- .github/workflows/run-tests.yml | 4 ++++ composer.json | 1 - tests/AuthContextQueueJobTest.php | 15 +++++++++++---- tests/AuthContextQueueListenerTest.php | 15 +++++++++++---- tests/AuthContextQueueNotificationTest.php | 13 +++++++++++-- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index d4c6b33..7c5bbe2 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -39,6 +39,10 @@ jobs: extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite coverage: none + - name: Remove pest-plugin-arch for PHP 8.0 + if: matrix.php == '8.0' + run: composer remove pestphp/pest-plugin-arch --dev --no-update + - name: Install dependencies run: | composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update diff --git a/composer.json b/composer.json index 01b8e81..0accd96 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,6 @@ "larastan/larastan": "^1.0|^2.9|^3.1", "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", "pestphp/pest": "^1.0|^2.0|^3.0", - "pestphp/pest-plugin-arch": "^1.0|^2.0|^3.0", "pestphp/pest-plugin-laravel": "^1.0|^2.0|^3.0", "phpstan/extension-installer": "^1.3", "phpstan/phpstan-deprecation-rules": "^1.1|^2.0", diff --git a/tests/AuthContextQueueJobTest.php b/tests/AuthContextQueueJobTest.php index 2d0fb97..6a5e4b5 100644 --- a/tests/AuthContextQueueJobTest.php +++ b/tests/AuthContextQueueJobTest.php @@ -1,5 +1,6 @@ serializeAndRestore(); + if (version_compare(Application::VERSION, '10.0', '>=')) { + Queue::fake()->serializeAndRestore(); + } else { + Queue::fake(); + } /** @var \Mockery\Mock $loggerSpy */ $loggerSpy = Mockery::spy('logger'); @@ -45,8 +50,6 @@ // Assert $response->assertSuccessful(); - Queue::assertCount(2); - Queue::assertPushed(TestWasAuthenticatedJob::class, function (TestWasAuthenticatedJob $job) use ($user) { return collect($job->middleware)->filter(function ($middleware) use ($user) { return get_class($middleware) === RestoreAuthenticatedContextMiddleware::class && @@ -105,7 +108,11 @@ it('handles unauthenticated requests correctly', function () { // Arrange - Queue::fake()->serializeAndRestore(); + if (version_compare(Application::VERSION, '10.0', '>=')) { + Queue::fake()->serializeAndRestore(); + } else { + Queue::fake(); + } // Act $response = $this->postJson('/test/dispatch-job'); diff --git a/tests/AuthContextQueueListenerTest.php b/tests/AuthContextQueueListenerTest.php index 4cbb4b5..57b19fe 100644 --- a/tests/AuthContextQueueListenerTest.php +++ b/tests/AuthContextQueueListenerTest.php @@ -1,5 +1,6 @@ serializeAndRestore(); + if (version_compare(Application::VERSION, '10.0', '>=')) { + Queue::fake()->serializeAndRestore(); + } else { + Queue::fake(); + } /** @var \Mockery\Mock $loggerSpy */ $loggerSpy = Mockery::spy('logger'); @@ -48,8 +53,6 @@ // Assert $response->assertSuccessful(); - Queue::assertCount(1); - Queue::assertPushed(CallQueuedListener::class, function (CallQueuedListener $job) use ($user) { return collect($job->middleware)->filter(function ($middleware) use ($user) { return get_class($middleware) === RestoreAuthenticatedContextMiddleware::class && @@ -96,7 +99,11 @@ it('handles unauthenticated requests correctly', function () { // Arrange - Queue::fake()->serializeAndRestore(); + if (version_compare(Application::VERSION, '10.0', '>=')) { + Queue::fake()->serializeAndRestore(); + } else { + Queue::fake(); + } // Arrange User::create([ diff --git a/tests/AuthContextQueueNotificationTest.php b/tests/AuthContextQueueNotificationTest.php index d0a9331..e9a4c17 100644 --- a/tests/AuthContextQueueNotificationTest.php +++ b/tests/AuthContextQueueNotificationTest.php @@ -1,5 +1,6 @@ serializeAndRestore(); + if (version_compare(Application::VERSION, '10.0', '>=')) { + Notification::fake()->serializeAndRestore(); + } else { + Notification::fake(); + } /** @var \Mockery\Mock $loggerSpy */ $loggerSpy = Mockery::spy('logger'); @@ -86,7 +91,11 @@ it('handles unauthenticated requests correctly', function () { // Arrange - Notification::fake()->serializeAndRestore(); + if (version_compare(Application::VERSION, '10.0', '>=')) { + Notification::fake()->serializeAndRestore(); + } else { + Notification::fake(); + } // Arrange $user = User::create([ From 7dd76bc6a2c083d10921cc9b7abedde6fa7728e7 Mon Sep 17 00:00:00 2001 From: datpmwork <9279315+datpmwork@users.noreply.github.com> Date: Fri, 4 Jul 2025 01:42:53 +0000 Subject: [PATCH 26/32] Fix styling --- tests/AuthContextQueueJobTest.php | 2 +- tests/AuthContextQueueListenerTest.php | 2 +- tests/AuthContextQueueNotificationTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/AuthContextQueueJobTest.php b/tests/AuthContextQueueJobTest.php index 6a5e4b5..a5fc91d 100644 --- a/tests/AuthContextQueueJobTest.php +++ b/tests/AuthContextQueueJobTest.php @@ -1,11 +1,11 @@ Date: Fri, 4 Jul 2025 08:53:20 +0700 Subject: [PATCH 27/32] Ignore Unsued Trait --- phpstan.neon.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 5fc50b3..ee1ad4d 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,8 +6,8 @@ parameters: paths: - src - config - excludePaths: - - tests/* + ignoreErrors: + - '#Trait .* is used zero times and is not analysed#' tmpDir: build/phpstan checkOctaneCompatibility: true checkModelProperties: true From a89e7a87cf72a1f62cb8c023e245a1b5280d0286 Mon Sep 17 00:00:00 2001 From: DatPM Date: Mon, 7 Jul 2025 15:46:16 +0700 Subject: [PATCH 28/32] Remove some devs packages while testing --- .github/workflows/run-tests.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 7c5bbe2..e51a327 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -39,9 +39,10 @@ jobs: extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite coverage: none - - name: Remove pest-plugin-arch for PHP 8.0 - if: matrix.php == '8.0' - run: composer remove pestphp/pest-plugin-arch --dev --no-update + - name: Remove dev packages for PHP 8.0 + run: | + composer remove larastan/larastan --dev --no-update + composer remove pestphp/pest-plugin-arch --dev --no-update - name: Install dependencies run: | From 851d2d65df783e464b68b348d0f5266f3ce29e03 Mon Sep 17 00:00:00 2001 From: DatPM Date: Tue, 8 Jul 2025 09:30:41 +0700 Subject: [PATCH 29/32] Preserves authentication context for queued jobs Ensures that the authenticated user's context is maintained when dispatching jobs to the queue. This is achieved by serializing the authenticated user's identifier and restoring it when the job is processed. Adds a trait to simplify middleware assignment for authenticated jobs. Also includes formatting rules for code style consistency. --- composer.json | 3 +- pint.json | 8 +++ src/LaravelAuthQueueServiceProvider.php | 12 +++- .../RestoreAuthenticatedContextMiddleware.php | 26 +++----- src/Traits/WasAuthenticated.php | 63 +------------------ tests/AuthContextQueueJobTest.php | 54 +++++++++++----- tests/AuthContextQueueListenerTest.php | 26 +++----- tests/AuthContextQueueNotificationTest.php | 12 ++-- tests/Controllers/TestController.php | 12 ++-- .../Jobs/TestWasAuthenticatedExtendedJob.php | 8 +++ tests/Jobs/TestWasAuthenticatedJob.php | 4 +- ...WasAuthenticatedWithSerializesModelJob.php | 21 +++++++ tests/Jobs/TestWasNotAuthenticatedJob.php | 4 +- tests/Listeners/TestEventSubscriber.php | 6 +- tests/Models/User.php | 2 +- tests/Notifications/TestNotification.php | 4 +- tests/TestCase.php | 8 +-- 17 files changed, 135 insertions(+), 138 deletions(-) create mode 100644 pint.json create mode 100644 tests/Jobs/TestWasAuthenticatedExtendedJob.php create mode 100644 tests/Jobs/TestWasAuthenticatedWithSerializesModelJob.php diff --git a/composer.json b/composer.json index 0accd96..f2bb68a 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,8 @@ "pestphp/pest-plugin-laravel": "^1.0|^2.0|^3.0", "phpstan/extension-installer": "^1.3", "phpstan/phpstan-deprecation-rules": "^1.1|^2.0", - "phpstan/phpstan-phpunit": "^1.3|^2.0" + "phpstan/phpstan-phpunit": "^1.3|^2.0", + "ext-json": "*" }, "autoload": { "psr-4": { diff --git a/pint.json b/pint.json new file mode 100644 index 0000000..553fe3a --- /dev/null +++ b/pint.json @@ -0,0 +1,8 @@ +{ + "preset": "laravel", + "rules": { + "ordered_imports": { + "sort_algorithm": "length" + } + } +} diff --git a/src/LaravelAuthQueueServiceProvider.php b/src/LaravelAuthQueueServiceProvider.php index 032f784..89cd936 100644 --- a/src/LaravelAuthQueueServiceProvider.php +++ b/src/LaravelAuthQueueServiceProvider.php @@ -2,9 +2,11 @@ namespace DatPM\LaravelAuthQueue; -use DatPM\LaravelAuthQueue\Guards\KernelGuard; +use Illuminate\Queue\Queue; use Illuminate\Support\Facades\Auth; use Illuminate\Support\ServiceProvider; +use DatPM\LaravelAuthQueue\Guards\KernelGuard; +use Illuminate\Contracts\Database\ModelIdentifier; class LaravelAuthQueueServiceProvider extends ServiceProvider { @@ -27,5 +29,13 @@ public function boot() 'driver' => 'kernel', 'provider' => config("auth.guards.{$defaultGuard}.provider"), ]]); + + Queue::createPayloadUsing(function () { + $user = auth()->user(); + $userPayload = new ModelIdentifier(get_class($user), $user->getQueueableId(), [], $user->getQueueableConnection()); + return [ + 'authUser' => serialize($userPayload), + ]; + }); } } diff --git a/src/Middlewares/RestoreAuthenticatedContextMiddleware.php b/src/Middlewares/RestoreAuthenticatedContextMiddleware.php index f461258..adddc9c 100644 --- a/src/Middlewares/RestoreAuthenticatedContextMiddleware.php +++ b/src/Middlewares/RestoreAuthenticatedContextMiddleware.php @@ -2,17 +2,13 @@ namespace DatPM\LaravelAuthQueue\Middlewares; -use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Support\Facades\Auth; +use Illuminate\Queue\SerializesModels; +use Illuminate\Contracts\Auth\Authenticatable; class RestoreAuthenticatedContextMiddleware { - protected $authUser; - - public function __construct($authUser) - { - $this->authUser = $authUser; - } + use SerializesModels; public function handle($command, callable $next) { @@ -20,8 +16,12 @@ public function handle($command, callable $next) $guard = auth(); - if (! empty($this->authUser)) { - $guard->setUser($this->authUser); + $embedUserData = data_get($command->job->payload(), 'authUser'); + if ($embedUserData) { + $embedUser = $this->restoreModel(unserialize($embedUserData)); + if ($embedUser instanceof Authenticatable) { + $guard->setUser($embedUser); + } } $response = $next($command); @@ -30,12 +30,4 @@ public function handle($command, callable $next) return $response; } - - /** - * @return Authenticatable|null - */ - public function getAuthUser() - { - return $this->authUser; - } } diff --git a/src/Traits/WasAuthenticated.php b/src/Traits/WasAuthenticated.php index f4f1325..e1477cf 100644 --- a/src/Traits/WasAuthenticated.php +++ b/src/Traits/WasAuthenticated.php @@ -6,72 +6,11 @@ trait WasAuthenticated { - protected $authenticatedUser; - - /** - * Override __sleep to work with SerializesModels - */ - public function __sleep() - { - // Ensure auth context is captured before serialization - $this->captureAuthContext(); - - // If using SerializesModels, call its __sleep method - if (in_array('Illuminate\Queue\SerializesModels', class_uses_recursive($this))) { - // Let SerializesModels handle its serialization - $properties = $this->__sleepSerializesModels(); - } else { - // Standard serialization - $properties = array_keys(get_object_vars($this)); - } - - return $properties; - } - - /** - * Handle SerializesModels __sleep if trait is used - */ - protected function __sleepSerializesModels() - { - $properties = array_keys(get_object_vars($this)); - - // Let SerializesModels do its magic - foreach ($properties as $property) { - $value = $this->{$property}; - if ($this->isSerializableModel($value)) { - $this->{$property} = $this->getSerializedPropertyValue($value); - } - } - - return $properties; - } - - /** - * Check if value should be serialized by SerializesModels - */ - protected function isSerializableModel($value) - { - return method_exists($this, 'getSerializedPropertyValue') && - (is_object($value) && method_exists($value, 'getQueueableId')); - } - - /** - * Capture and customize auth context - */ - protected function captureAuthContext() - { - $user = auth()->user(); - if ($user) { - // Customize serialization based on your needs - $this->authenticatedUser = $user; - } - } - /** * The job should go through AuthenticatedMiddleware */ public function middleware() { - return [new RestoreAuthenticatedContextMiddleware($this->authenticatedUser ?: auth()->user())]; + return [new RestoreAuthenticatedContextMiddleware()]; } } diff --git a/tests/AuthContextQueueJobTest.php b/tests/AuthContextQueueJobTest.php index a5fc91d..cfe000a 100644 --- a/tests/AuthContextQueueJobTest.php +++ b/tests/AuthContextQueueJobTest.php @@ -1,15 +1,18 @@ assertSuccessful(); - Queue::assertPushed(TestWasAuthenticatedJob::class, function (TestWasAuthenticatedJob $job) use ($user) { - return collect($job->middleware)->filter(function ($middleware) use ($user) { - return get_class($middleware) === RestoreAuthenticatedContextMiddleware::class && - $middleware->getAuthUser()->getAuthIdentifier() === $user->getKey(); - }); - }); + Queue::assertPushed(TestWasAuthenticatedJob::class, 1); Queue::assertPushed(TestWasNotAuthenticatedJob::class, 1); + Queue::assertPushed(TestWasAuthenticatedWithSerializesModelJob::class, 1); + Queue::assertPushed(TestWasAuthenticatedExtendedJob::class, 1); }); it('preserves auth context when Job is executed', function () { @@ -78,11 +78,10 @@ // Assert $response->assertSuccessful(); - expect(DB::table('jobs')->count())->toBe(2); + expect(DB::table('jobs')->count())->toBe(4); // Reset Auth to prevent reuse auth data of the above API auth()->guard()->forgetUser(); - $this->artisan('queue:work --once'); // Assert logger was called with correct values @@ -94,11 +93,36 @@ ->with('Auth Check: 1') ->once(); + auth()->guard()->forgetUser(); + $this->artisan('queue:work --once'); + + // Assert logger was called with correct values + $loggerSpy->shouldHaveReceived('info') + ->with("Auth ID: {$user->id}") + ->twice(); + + $loggerSpy->shouldHaveReceived('info') + ->with('Auth Check: 1') + ->twice(); + + auth()->guard()->forgetUser(); + $this->artisan('queue:work --once'); + + // Assert logger was called with correct values + $loggerSpy->shouldHaveReceived('info') + ->with("Auth ID: {$user->id}") + ->times(3); + + $loggerSpy->shouldHaveReceived('info') + ->with('Auth Check: 1') + ->times(3); + + auth()->guard()->forgetUser(); $this->artisan('queue:work --once'); // Assert logger was called with correct values $loggerSpy->shouldHaveReceived('info') - ->with('Auth ID: ') + ->with("Auth ID: ") ->once(); $loggerSpy->shouldHaveReceived('info') diff --git a/tests/AuthContextQueueListenerTest.php b/tests/AuthContextQueueListenerTest.php index 2bede9f..2ba8fa4 100644 --- a/tests/AuthContextQueueListenerTest.php +++ b/tests/AuthContextQueueListenerTest.php @@ -1,16 +1,16 @@ assertSuccessful(); - Queue::assertPushed(CallQueuedListener::class, function (CallQueuedListener $job) use ($user) { - return collect($job->middleware)->filter(function ($middleware) use ($user) { - return get_class($middleware) === RestoreAuthenticatedContextMiddleware::class && - $middleware->getAuthUser()->getAuthIdentifier() === $user->getKey(); - }); - }); + Queue::assertPushed(CallQueuedListener::class); }); it('preserves auth context when Listener is executed', function () { @@ -117,12 +112,7 @@ // Assert $response->assertSuccessful(); - Queue::assertPushed(CallQueuedListener::class, function (CallQueuedListener $job) { - return collect($job->middleware)->filter(function ($middleware) { - return get_class($middleware) === RestoreAuthenticatedContextMiddleware::class && - empty($middleware->getAuthUser()); - }); - }); + Queue::assertPushed(CallQueuedListener::class); }); afterEach(function () { diff --git a/tests/AuthContextQueueNotificationTest.php b/tests/AuthContextQueueNotificationTest.php index 094b4c6..6863443 100644 --- a/tests/AuthContextQueueNotificationTest.php +++ b/tests/AuthContextQueueNotificationTest.php @@ -1,15 +1,15 @@ json(['status' => 'dispatched job']); diff --git a/tests/Jobs/TestWasAuthenticatedExtendedJob.php b/tests/Jobs/TestWasAuthenticatedExtendedJob.php new file mode 100644 index 0000000..a475c24 --- /dev/null +++ b/tests/Jobs/TestWasAuthenticatedExtendedJob.php @@ -0,0 +1,8 @@ +info('Auth ID: '.auth()->id()); + logger()->info('Auth Check: '.auth()->check()); + } +} diff --git a/tests/Jobs/TestWasNotAuthenticatedJob.php b/tests/Jobs/TestWasNotAuthenticatedJob.php index d5f6a3f..44b1a6e 100644 --- a/tests/Jobs/TestWasNotAuthenticatedJob.php +++ b/tests/Jobs/TestWasNotAuthenticatedJob.php @@ -3,10 +3,10 @@ namespace DatPM\LaravelAuthQueue\Tests\Jobs; use Illuminate\Bus\Queueable; +use Illuminate\Queue\SerializesModels; +use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; class TestWasNotAuthenticatedJob implements ShouldQueue { diff --git a/tests/Listeners/TestEventSubscriber.php b/tests/Listeners/TestEventSubscriber.php index 4b6e157..36e3660 100644 --- a/tests/Listeners/TestEventSubscriber.php +++ b/tests/Listeners/TestEventSubscriber.php @@ -2,11 +2,11 @@ namespace DatPM\LaravelAuthQueue\Tests\Listeners; -use DatPM\LaravelAuthQueue\Tests\Models\User; -use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Events\Dispatcher; +use Illuminate\Contracts\Queue\ShouldQueue; +use DatPM\LaravelAuthQueue\Tests\Models\User; +use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; class TestEventSubscriber implements ShouldQueue { diff --git a/tests/Models/User.php b/tests/Models/User.php index d0a2eef..b550c25 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -2,9 +2,9 @@ namespace DatPM\LaravelAuthQueue\Tests\Models; +use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; -use Illuminate\Notifications\Notifiable; class User extends Authenticatable { diff --git a/tests/Notifications/TestNotification.php b/tests/Notifications/TestNotification.php index 9dfa5c6..0c7e532 100644 --- a/tests/Notifications/TestNotification.php +++ b/tests/Notifications/TestNotification.php @@ -2,10 +2,10 @@ namespace DatPM\LaravelAuthQueue\Tests\Notifications; -use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; +use Illuminate\Contracts\Queue\ShouldQueue; +use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; class TestNotification extends Notification implements ShouldQueue { diff --git a/tests/TestCase.php b/tests/TestCase.php index 42dd4b5..b9549c3 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,12 +2,12 @@ namespace DatPM\LaravelAuthQueue\Tests; -use DatPM\LaravelAuthQueue\LaravelAuthQueueServiceProvider; -use Illuminate\Contracts\Auth\Authenticatable; -use Illuminate\Database\Eloquent\Factories\Factory; -use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Contracts\Auth\Authenticatable; use Orchestra\Testbench\TestCase as Orchestra; +use Illuminate\Database\Eloquent\Factories\Factory; +use DatPM\LaravelAuthQueue\LaravelAuthQueueServiceProvider; /** * @method \Illuminate\Foundation\Testing\TestCase actingAs(Authenticatable $user, string|null $guard = null) From 93a9667edfb0dd5443e66c2c9a476dc672e66b19 Mon Sep 17 00:00:00 2001 From: datpmwork <9279315+datpmwork@users.noreply.github.com> Date: Tue, 8 Jul 2025 02:31:10 +0000 Subject: [PATCH 30/32] Fix styling --- src/LaravelAuthQueueServiceProvider.php | 1 + src/Traits/WasAuthenticated.php | 2 +- tests/AuthContextQueueJobTest.php | 3 +-- tests/AuthContextQueueListenerTest.php | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/LaravelAuthQueueServiceProvider.php b/src/LaravelAuthQueueServiceProvider.php index 89cd936..b690b77 100644 --- a/src/LaravelAuthQueueServiceProvider.php +++ b/src/LaravelAuthQueueServiceProvider.php @@ -33,6 +33,7 @@ public function boot() Queue::createPayloadUsing(function () { $user = auth()->user(); $userPayload = new ModelIdentifier(get_class($user), $user->getQueueableId(), [], $user->getQueueableConnection()); + return [ 'authUser' => serialize($userPayload), ]; diff --git a/src/Traits/WasAuthenticated.php b/src/Traits/WasAuthenticated.php index e1477cf..6fb102a 100644 --- a/src/Traits/WasAuthenticated.php +++ b/src/Traits/WasAuthenticated.php @@ -11,6 +11,6 @@ trait WasAuthenticated */ public function middleware() { - return [new RestoreAuthenticatedContextMiddleware()]; + return [new RestoreAuthenticatedContextMiddleware]; } } diff --git a/tests/AuthContextQueueJobTest.php b/tests/AuthContextQueueJobTest.php index cfe000a..96b2933 100644 --- a/tests/AuthContextQueueJobTest.php +++ b/tests/AuthContextQueueJobTest.php @@ -5,7 +5,6 @@ use Illuminate\Support\Facades\Route; use Illuminate\Foundation\Application; use Illuminate\Support\Facades\Schema; -use Illuminate\Queue\SerializesModels; use DatPM\LaravelAuthQueue\Tests\Models\User; use DatPM\LaravelAuthQueue\Tests\Controllers\TestController; use DatPM\LaravelAuthQueue\Tests\Jobs\TestWasAuthenticatedJob; @@ -122,7 +121,7 @@ // Assert logger was called with correct values $loggerSpy->shouldHaveReceived('info') - ->with("Auth ID: ") + ->with('Auth ID: ') ->once(); $loggerSpy->shouldHaveReceived('info') diff --git a/tests/AuthContextQueueListenerTest.php b/tests/AuthContextQueueListenerTest.php index 2ba8fa4..f8f4f07 100644 --- a/tests/AuthContextQueueListenerTest.php +++ b/tests/AuthContextQueueListenerTest.php @@ -10,7 +10,6 @@ use DatPM\LaravelAuthQueue\Tests\Models\User; use DatPM\LaravelAuthQueue\Tests\Controllers\TestController; use DatPM\LaravelAuthQueue\Tests\Listeners\TestEventSubscriber; -use DatPM\LaravelAuthQueue\Middlewares\RestoreAuthenticatedContextMiddleware; beforeEach(function () { Schema::create('users', function ($table) { From 39ed21b4fbf39b1de1c7f9df3a23913551494bea Mon Sep 17 00:00:00 2001 From: DatPM Date: Tue, 8 Jul 2025 10:18:54 +0700 Subject: [PATCH 31/32] Fixes auth context in queued jobs Ensures the correct authentication context is preserved when dispatching jobs to the queue. This prevents issues where the authenticated user is not available within the job's execution context. Adds a check to only serialize the auth user if the job uses the `WasAuthenticated` trait. This avoids potential errors when the job does not require authentication. Updates the supported PHP and Laravel versions in the README. --- README.md | 12 +---- src/LaravelAuthQueueServiceProvider.php | 12 ++++- tests/AuthContextQueueJobTest.php | 71 +++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index aae0c5c..8fcb0ce 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ asynchronous operations. ## Requirements -- PHP ^8.2 -- Laravel 10.x|11.x|12.x +- PHP ^7.4 | > 8.0 +- Laravel 9.x | 10.x | 11.x | 12.x ## Support us @@ -97,14 +97,6 @@ class SampleSubscriber implements ShouldQueue Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. -## Contributing - -Please see [CONTRIBUTING](CONTRIBUTING.md) for details. - -## Security Vulnerabilities - -Please review [our security policy](../../security/policy) on how to report security vulnerabilities. - ## Credits - [datpmwork](https://github.com/datpmwork) diff --git a/src/LaravelAuthQueueServiceProvider.php b/src/LaravelAuthQueueServiceProvider.php index 89cd936..e8281eb 100644 --- a/src/LaravelAuthQueueServiceProvider.php +++ b/src/LaravelAuthQueueServiceProvider.php @@ -7,6 +7,7 @@ use Illuminate\Support\ServiceProvider; use DatPM\LaravelAuthQueue\Guards\KernelGuard; use Illuminate\Contracts\Database\ModelIdentifier; +use DatPM\LaravelAuthQueue\Traits\WasAuthenticated; class LaravelAuthQueueServiceProvider extends ServiceProvider { @@ -30,8 +31,17 @@ public function boot() 'provider' => config("auth.guards.{$defaultGuard}.provider"), ]]); - Queue::createPayloadUsing(function () { + Queue::createPayloadUsing(function ($connectionName, $queue, $payload) { + # Skip attaching authUser when the job does not use WasAuthenticated Trait + if (!in_array(WasAuthenticated::class, class_uses_recursive($payload['displayName']))) { + return []; + } + $user = auth()->user(); + if (empty($user)) { + return []; + } + $userPayload = new ModelIdentifier(get_class($user), $user->getQueueableId(), [], $user->getQueueableConnection()); return [ 'authUser' => serialize($userPayload), diff --git a/tests/AuthContextQueueJobTest.php b/tests/AuthContextQueueJobTest.php index cfe000a..4896e6f 100644 --- a/tests/AuthContextQueueJobTest.php +++ b/tests/AuthContextQueueJobTest.php @@ -130,6 +130,77 @@ ->once(); }); +it('preserves auth context (null) when Job is executed', function () { + Queue::setDefaultDriver('database'); + + /** @var \Mockery\Mock $loggerSpy */ + $loggerSpy = Mockery::spy('logger'); + $this->app->instance('log', $loggerSpy); + + // Arrange + $user = User::create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + // Act + $response = $this->postJson('/test/dispatch-job'); + + // Assert + $response->assertSuccessful(); + + expect(DB::table('jobs')->count())->toBe(4); + + // Reset Auth to prevent reuse auth data of the above API + auth()->guard()->forgetUser(); + $this->artisan('queue:work --once'); + + // Assert logger was called with correct values + $loggerSpy->shouldHaveReceived('info') + ->with("Auth ID: ") + ->once(); + + $loggerSpy->shouldHaveReceived('info') + ->with('Auth Check: ') + ->once(); + + auth()->guard()->forgetUser(); + $this->artisan('queue:work --once'); + + // Assert logger was called with correct values + $loggerSpy->shouldHaveReceived('info') + ->with("Auth ID: ") + ->twice(); + + $loggerSpy->shouldHaveReceived('info') + ->with('Auth Check: ') + ->twice(); + + auth()->guard()->forgetUser(); + $this->artisan('queue:work --once'); + + // Assert logger was called with correct values + $loggerSpy->shouldHaveReceived('info') + ->with("Auth ID: ") + ->times(3); + + $loggerSpy->shouldHaveReceived('info') + ->with('Auth Check: ') + ->times(3); + + auth()->guard()->forgetUser(); + $this->artisan('queue:work --once'); + + // Assert logger was called with correct values + $loggerSpy->shouldHaveReceived('info') + ->with("Auth ID: ") + ->times(4); + + $loggerSpy->shouldHaveReceived('info') + ->with('Auth Check: ') + ->times(4); +}); + it('handles unauthenticated requests correctly', function () { // Arrange if (version_compare(Application::VERSION, '10.0', '>=')) { From fa9b2c9015c309871d0d5a4d85d0aa1149ff4434 Mon Sep 17 00:00:00 2001 From: datpmwork <9279315+datpmwork@users.noreply.github.com> Date: Tue, 8 Jul 2025 03:20:49 +0000 Subject: [PATCH 32/32] Fix styling --- src/LaravelAuthQueueServiceProvider.php | 4 ++-- tests/AuthContextQueueJobTest.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/LaravelAuthQueueServiceProvider.php b/src/LaravelAuthQueueServiceProvider.php index 8d330d3..a3b9997 100644 --- a/src/LaravelAuthQueueServiceProvider.php +++ b/src/LaravelAuthQueueServiceProvider.php @@ -32,8 +32,8 @@ public function boot() ]]); Queue::createPayloadUsing(function ($connectionName, $queue, $payload) { - # Skip attaching authUser when the job does not use WasAuthenticated Trait - if (!in_array(WasAuthenticated::class, class_uses_recursive($payload['displayName']))) { + // Skip attaching authUser when the job does not use WasAuthenticated Trait + if (! in_array(WasAuthenticated::class, class_uses_recursive($payload['displayName']))) { return []; } diff --git a/tests/AuthContextQueueJobTest.php b/tests/AuthContextQueueJobTest.php index a3edbef..3ab7d73 100644 --- a/tests/AuthContextQueueJobTest.php +++ b/tests/AuthContextQueueJobTest.php @@ -156,7 +156,7 @@ // Assert logger was called with correct values $loggerSpy->shouldHaveReceived('info') - ->with("Auth ID: ") + ->with('Auth ID: ') ->once(); $loggerSpy->shouldHaveReceived('info') @@ -168,7 +168,7 @@ // Assert logger was called with correct values $loggerSpy->shouldHaveReceived('info') - ->with("Auth ID: ") + ->with('Auth ID: ') ->twice(); $loggerSpy->shouldHaveReceived('info') @@ -180,7 +180,7 @@ // Assert logger was called with correct values $loggerSpy->shouldHaveReceived('info') - ->with("Auth ID: ") + ->with('Auth ID: ') ->times(3); $loggerSpy->shouldHaveReceived('info') @@ -192,7 +192,7 @@ // Assert logger was called with correct values $loggerSpy->shouldHaveReceived('info') - ->with("Auth ID: ") + ->with('Auth ID: ') ->times(4); $loggerSpy->shouldHaveReceived('info')