composer-attribute-collector icon indicating copy to clipboard operation
composer-attribute-collector copied to clipboard

Plugin Loads Before Custom Autoload Logic, Causing Undefined Class Errors

Open abdokouta opened this issue 1 year ago • 1 comments

Bug Report

Package: olvlvl/composer-attribute-collector

Issue Summary

The Plugin class from olvlvl/composer-attribute-collector loads before my custom autoload logic, which registers classes dynamically. As a result, classes that should be available during the autoload process are not found, leading to undefined class errors.

I have a custom command (php artisan autoload) that is responsible for loading additional classes after the post-autoload-dump event. However, since the Plugin class registers its autoload mappings first, my classes are not recognized when the composer-attribute-collector runs.

Steps to Reproduce

  1. Define a custom autoloading command (php artisan autoload) that dynamically loads classes after the post-autoload-dump event.

  2. Configure olvlvl/composer-attribute-collector with the following in composer.json:

    "extra": {
        "class": "olvlvl\\ComposerAttributeCollector\\Plugin",
        "composer-attribute-collector": {
            "include": [
                "tests"
            ],
            "exclude": [
                "tests/Acme/PSR4/IncompatibleSignature.php"
            ]
        }
    }
    
  3. Run composer dump-autoload or any related command.

  4. Observe that classes expected by my command are not loaded, resulting in class not found errors.

Expected Behavior

The Plugin class from olvlvl/composer-attribute-collector should allow custom autoload logic to run before it attempts to register classes, or provide a way to delay its execution until after my custom autoload process has completed.

Actual Behavior

The Plugin class is executed first, which results in classes being unavailable for the autoload process, leading to undefined class errors.

Environment

  • PHP version: 8.2
  • Composer version: 2.7.9
  • olvlvl/composer-attribute-collector version: @latest

Possible Solution

Allow the Plugin class to be manually triggered after custom autoload logic is executed, or provide a configuration option to defer its execution until after custom autoload registration is complete.

Additional Context

I currently run a custom command (php artisan autoload) in the post-autoload-dump section of composer.json:

"scripts": {
    "post-autoload-dump": [
        "@php artisan autoload"
    ]
}

However, the Plugin class runs too early, preventing my autoload command from functioning properly.

abdokouta avatar Sep 16 '24 17:09 abdokouta

Thanks for opening the issue. Could you try the following?

1. Comment the listener registration in olvlvl/composer-attribute-collector/src/Plugin.php:

    public static function getSubscribedEvents(): array
    {
        return [
            // 'post-autoload-dump' => 'onPostAutoloadDump',
        ];
    }

2. Add the plugin after your autoload registration:

"scripts": {
    "post-autoload-dump": [
        "@php artisan autoload",
        "olvlvl\ComposerAttributeCollector\Plugin::onPostAutoloadDump"
    ]
}

olvlvl avatar Sep 20 '24 06:09 olvlvl

@abdokouta could you try the branch over there? https://github.com/olvlvl/composer-attribute-collector/pull/35

{
  "require": {
    "olvlvl/composer-attribute-collector": "dev-run-as-command as 3.0"
  }
}

olvlvl avatar Jun 11 '25 13:06 olvlvl

@abdokouta I've released v2.1.0. Can you tell me if it fixed your issue?

olvlvl avatar Jun 17 '25 11:06 olvlvl

@olvlvl, I encountered a fatal error while installing and using olvlvl/composer-attribute-collector in a fresh Laravel 11 project using Composer 2.7 and PHP 8.3/8.4. It appears the plugin is still relying on the legacy Composer\Plugin\PluginInterface, which has been removed in recent Composer versions.

🧪 Error Summary

Fatal error: Uncaught Error: Interface "Composer\Plugin\PluginInterface" not found in /vendor/olvlvl/composer-attribute-collector/src/Plugin.php:21

🧾 Full Stack Trace

The command "'/vendor/olvlvl/composer-attribute-collector/collector.php' '--' 'O:40:...'" failed.
Exit Code: 255 (Unknown error)
Fatal error: Uncaught Error: Interface "Composer\Plugin\PluginInterface" not found in /vendor/olvlvl/composer-attribute-collector/src/Plugin.php:21
Stack trace:
#0 .../ClassLoader.php(576): include()
#1 .../ClassLoader.php(427): Composer\Autoload\ClassLoader::loadClass()
#2 .../Collector.php(84): Composer\Autoload\ClassLoader->loadClass()
#3 .../Collector.php(35): Collector->buildDefaultDatastore()
#4 .../collector.php(42): Collector->dump()
#5 {main}

💻 Environment • OS: macOS (Apple Silicon) • PHP: 8.3.8 / 8.4-dev (via Herd) • Composer: 2.7.1 • Laravel: 11.x • Plugin version: olvlvl/composer-attribute-collector v0.14.0

📌 Suggestion

Please consider updating the plugin to use the new Composer 2 plugin system or at least guard against usage when the interface is unavailable.

abdokouta avatar Jun 17 '25 11:06 abdokouta

I've tested with Composer v2.4.0 and v2.8.9. The tests are passing. Besides, the class Composer\Plugin\PluginInterface is available in both versions. Could you share your composer.json?

Plugin version: olvlvl/composer-attribute-collector v0.14.0

Please, use v2.1.0.

olvlvl avatar Jun 17 '25 11:06 olvlvl

@olvlvl adding "composer/composer": "^2.8", to the require-dev fixed the issue

abdokouta avatar Jun 17 '25 12:06 abdokouta

@olvlvl I have tried to generate the attributes file, but not detecting any attributes. Here is my composer.json


{
    "$schema": "https://getcomposer.org/schema.json",
    "name": "laravel/laravel",
    "type": "project",
    "description": "The skeleton application for the Laravel framework.",
    "keywords": [
        "laravel",
        "framework"
    ],
    "license": "MIT",
    "require": {
        "php": "^8.2",
        "laravel/framework": "^12.0",
        "laravel/tinker": "^2.10.1",
        "olvlvl/composer-attribute-collector": "^2.1"
    },
    "require-dev": {
        "composer/composer": "^2.8",
        "fakerphp/faker": "^1.23",
        "laravel/pail": "^1.2.2",
        "laravel/pint": "^1.13",
        "laravel/sail": "^1.41",
        "mockery/mockery": "^1.6",
        "nunomaduro/collision": "^8.6",
        "phpunit/phpunit": "^11.5.3"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },
    "scripts": {
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi"
        ],
        "post-update-cmd": [
            "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
        ],
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi",
            "@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
            "@php artisan migrate --graceful --ansi"
        ],
        "dev": [
            "Composer\\Config::disableProcessTimeout",
            "npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite"
        ],
        "test": [
            "@php artisan config:clear --ansi",
            "@php artisan test"
        ]
    },
    "extra": {
        "laravel": {
            "dont-discover": []
        },
        "composer-attribute-collector": {
            "include": [
                "./app"
            ]
        }
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true,
        "allow-plugins": {
            "olvlvl/composer-attribute-collector": true,
            "pestphp/pest-plugin": true,
            "php-http/discovery": true
        }
    },
    "minimum-stability": "stable",
    "prefer-stable": true
}

abdokouta avatar Jun 17 '25 12:06 abdokouta

I think there was an issue with the v2.1.0 tag because the collector.php command was not available. I refreshed the tag.

I've created a fresh Laravel app, added a sample attribute, and tagged a couple of classes. I've added my plugin, and all went well. I've created a case over here. Please have a look.

https://github.com/olvlvl/composer-attribute-collector/pull/42

olvlvl avatar Jun 17 '25 13:06 olvlvl

I've merged the Laravel use case. It's tested with Composer v2.4.0 and the latest version, running with PHP 8.2 and 8.4.

I'm closing this issue. Please reopen if the problem persists.

olvlvl avatar Jun 18 '25 11:06 olvlvl

@olvlvl now it's working

Image

abdokouta avatar Jun 18 '25 11:06 abdokouta

Yay! Thanks for checking.

olvlvl avatar Jun 18 '25 11:06 olvlvl

@olvlvl I'd love to discuss potential collaboration on achieving full Laravel compatibility for the attribute system, covering key features like Controllers, Routes, Middlewares, Guards, and more. Please let me know if you're interested!

abdokouta avatar Jun 18 '25 11:06 abdokouta

I'm interested. Let's have a Google Meet or something. I'm mostly available next week.

olvlvl avatar Jun 18 '25 12:06 olvlvl

@olvlvl please share ur email id

abdokouta avatar Jun 18 '25 13:06 abdokouta

[email protected]

olvlvl avatar Jun 18 '25 13:06 olvlvl