{"id":23542712,"url":"https://github.com/olvlvl/composer-attribute-collector","last_synced_at":"2025-05-16T03:02:11.331Z","repository":{"id":62780848,"uuid":"561528564","full_name":"olvlvl/composer-attribute-collector","owner":"olvlvl","description":"A convenient and near zero-cost way to retrieve targets of PHP 8 attributes","archived":false,"fork":false,"pushed_at":"2024-11-29T13:10:54.000Z","size":109,"stargazers_count":159,"open_issues_count":3,"forks_count":3,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-05-13T10:47:09.479Z","etag":null,"topics":["attributes","composer-plugin","php"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/olvlvl.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-03T22:18:58.000Z","updated_at":"2025-05-04T13:21:48.000Z","dependencies_parsed_at":"2024-11-29T14:22:13.416Z","dependency_job_id":"27cc4697-0260-4667-a742-2fc71047a39d","html_url":"https://github.com/olvlvl/composer-attribute-collector","commit_stats":{"total_commits":34,"total_committers":2,"mean_commits":17.0,"dds":0.02941176470588236,"last_synced_commit":"a3d45a2e9bab87e31d07652c47d12a6bcc7ac2b1"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olvlvl%2Fcomposer-attribute-collector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olvlvl%2Fcomposer-attribute-collector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olvlvl%2Fcomposer-attribute-collector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olvlvl%2Fcomposer-attribute-collector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/olvlvl","download_url":"https://codeload.github.com/olvlvl/composer-attribute-collector/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254459077,"owners_count":22074604,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["attributes","composer-plugin","php"],"created_at":"2024-12-26T06:14:14.197Z","updated_at":"2025-05-16T03:02:11.305Z","avatar_url":"https://github.com/olvlvl.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# composer-attribute-collector\n\n[![Release](https://img.shields.io/packagist/v/olvlvl/composer-attribute-collector.svg)](https://packagist.org/packages/olvlvl/composer-attribute-collector)\n[![Code Coverage](https://coveralls.io/repos/github/olvlvl/composer-attribute-collector/badge.svg?branch=main)](https://coveralls.io/r/olvlvl/composer-attribute-collector?branch=main)\n[![Downloads](https://img.shields.io/packagist/dt/olvlvl/composer-attribute-collector.svg)](https://packagist.org/packages/olvlvl/composer-attribute-collector)\n\n**composer-attribute-collector** is a plugin for [Composer][]. Its ambition is to provide a\nconvenient way—and near zero cost—to retrieve targets of PHP 8 attributes. After the autoloader has\nbeen dumped, the plugin collects attribute targets and generates a static file. These targets can be\nretrieved through a convenient interface, without reflection. The plugin is useful when you need to\n_discover_ attribute targets in a codebase—for known targets you can use reflection.\n\n\n\n#### Features\n\n- Little configuration\n- No reflection in the generated file\n- No impact on performance\n- No dependency (except Composer of course)\n- A single interface to get attribute targets: classes, methods, and properties\n- Can cache discoveries to speed up consecutive runs.\n\n\u003e [!NOTE]\n\u003e Currently, the plugin supports class, method, and property targets.\n\u003e You're welcome to [contribute](CONTRIBUTING.md) if you're interested in expending its support.\n\n\n\n#### Usage\n\nThe following example demonstrates how targets and their attributes can be retrieved:\n\n```php\n\u003c?php\n\nuse olvlvl\\ComposerAttributeCollector\\Attributes;\nuse Symfony\\Component\\Messenger\\Attribute\\AsMessageHandler;\nuse Symfony\\Component\\Routing\\Annotation\\Route;\nuse Doctrine\\ORM\\Mapping\\Column;\n\nrequire_once 'vendor/autoload.php';\nrequire_once 'vendor/attributes.php'; // \u003c-- the file created by the plugin\n\n// Find the target classes of the AsMessageHandler attribute.\nforeach (Attributes::findTargetClasses(AsMessageHandler::class) as $target) {\n    // $target-\u003eattribute is an instance of the specified attribute\n    // with the actual data.\n    var_dump($target-\u003eattribute, $target-\u003ename);\n}\n\n// Find the target methods of the Route attribute.\nforeach (Attributes::findTargetMethods(Route::class) as $target) {\n    var_dump($target-\u003eattribute, $target-\u003eclass, $target-\u003ename);\n}\n\n// Find the target properties of the Column attribute.\nforeach (Attributes::findTargetProperties(Column::class) as $target) {\n    var_dump($target-\u003eattribute, $target-\u003eclass, $target-\u003ename);\n}\n\n// Filter target methods using a predicate.\n// You can also filter target classes and properties.\n$predicate = fn($attribute) =\u003e is_a($attribute, Route::class, true);\n# or\n$predicate = Attributes::predicateForAttributeInstanceOf(Route::class);\n\nforeach (Attributes::filterTargetMethods($predicate) as $target) {\n    var_dump($target-\u003eattribute, $target-\u003eclass, $target-\u003ename);\n}\n\n// Find class, method, and property attributes for the ArticleController class.\n$attributes = Attributes::forClass(ArticleController::class);\n\nvar_dump($attributes-\u003eclassAttributes);\nvar_dump($attributes-\u003emethodsAttributes);\nvar_dump($attributes-\u003epropertyAttributes);\n```\n\n\n\n## Getting started\n\nHere are a few steps to get you started.\n\n### 1\\. Configure the plugin\n\nThe plugin only inspects paths and files specified in the configuration with the `include` property.\nThat is usually your \"src\" directory. Add this section to your `composer.json` file to enable the\ngeneration of the \"attributes\" file when the autoloader is dumped.\n\n```json\n{\n  \"extra\": {\n    \"composer-attribute-collector\": {\n      \"include\": [\n        \"src\"\n      ]\n    }\n  }\n}\n```\n\nCheck the [Configuration options](#configuration) for more details.\n\n\n\n### 2\\. Install the plugin\n\nUse [Composer][] to install the plugin.\nYou will be asked if you trust the plugin and wish to activate it, select `y` to proceed.\n\n```shell\ncomposer require olvlvl/composer-attribute-collector\n```\n\nYou should see log messages similar to this:\n\n```\nGenerating autoload files\nGenerating attributes file\nGenerated attributes file in 9.137 ms\nGenerated autoload files\n```\n\n\u003e [!TIP]\n\u003e See the [Frequently Asked Questions](#frequently-asked-questions) section\n\u003e to automatically refresh the \"attributes\" file during development.\n\n\n\n### 3\\. Autoload the \"attributes\" file\n\nYou can require the \"attributes\" file using `require_once 'vendor/attributes.php';` but you might\nprefer to use Composer's autoloading feature:\n\n```json\n{\n  \"autoloading\": {\n    \"files\": [\n      \"vendor/attributes.php\"\n    ]\n  }\n}\n```\n\n\n\n## Configuration\n\nHere are a few ways you can configure the plugin.\n\n\n\n### Including paths or files ([root-only][])\n\nUse the `include` property to define the paths or files to inspect for attributes. Without this\nproperty, the \"attributes\" file will be empty.\n\nThe specified paths are relative to the `composer.json` file, and the `{vendor}` placeholder is\nreplaced with the path to the vendor folder.\n\n```json\n{\n  \"extra\": {\n    \"composer-attribute-collector\": {\n      \"include\": [\n        \"path-or-file/to/include\"\n      ]\n    }\n  }\n}\n```\n\n### Excluding paths or files ([root-only][])\n\nUse the `exclude` property to exclude paths or files from inspection. This is handy when files\ncause issues or have side effects.\n\nThe specified paths are relative to the `composer.json` file, and the `{vendor}` placeholder is\nreplaced with the path to the vendor folder.\n\n```json\n{\n  \"extra\": {\n    \"composer-attribute-collector\": {\n      \"exclude\": [\n        \"path-or-file/to/exclude\"\n      ]\n    }\n  }\n}\n```\n\n### Cache discoveries between runs\n\nThe plugin is able to maintain a cache to reuse discoveries between runs. To enable the cache,\nset the environment variable `COMPOSER_ATTRIBUTE_COLLECTOR_USE_CACHE` to `1`, `yes`, or `true`.\nCache items are persisted in the `.composer-attribute-collector` directory, you might want to add\nit to your `.gitignore` file.\n\n```shell\nCOMPOSER_ATTRIBUTE_COLLECTOR_USE_CACHE=1 composer dump-autoload\n```\n\n\n\n## Test drive with the Symfony Demo\n\nYou can try the plugin with a fresh installation of the [Symfony Demo Application](https://github.com/symfony/demo).\n\n\u003e [!TIP]\n\u003e The demo application configured with the plugin is [available on GitHub](https://github.com/olvlvl/composer-attribute-collector-usecase-symfony).\n\nSee the [Getting started](#getting-started) section to set up the plugin. If all went well, the file\n`vendor/attributes.php` should be available.\n\nNow, you can try to get the controller methods tagged as routes. Create a PHP file with the\nfollowing content and run it:\n\n```php\n\u003c?php\n\nuse olvlvl\\ComposerAttributeCollector\\Attributes;\nuse Symfony\\Component\\Routing\\Annotation\\Route;\n\nrequire_once 'vendor/autoload.php';\n\n$predicate = Attributes::predicateForAttributeInstanceOf(Route::class);\n$targets = Attributes::filterTargetMethods($predicate);\n\nforeach ($targets as $target) {\n    echo \"action: $target-\u003eclass#$target-\u003ename, path: {$target-\u003eattribute-\u003egetPath()}\\n\";\n}\n```\n\nYou should see an output similar to the following excerpt:\n\n```\naction: App\\Controller\\BlogController#index, path: /\naction: App\\Controller\\BlogController#index, path: /rss.xml\naction: App\\Controller\\BlogController#index, path: /page/{page\u003c[1-9]\\d{0,8}\u003e}\naction: App\\Controller\\BlogController#postShow, path: /posts/{slug}\naction: App\\Controller\\BlogController#commentNew, path: /comment/{postSlug}/new\naction: App\\Controller\\BlogController#search, path: /search\n```\n\n\n\n## Frequently Asked Questions\n\n**Do I need to generate an optimized autoloader?**\n\nYou don't need to generate an optimized autoloader for this to work. The plugin uses code similar\nto Composer to find classes. Anything that works with Composer should work with the plugin.\n\n**Can I use the plugin during development?**\n\nYes, you can use the plugin during development, but keep in mind the \"attributes\" file is only\ngenerated after the autoloader is dumped. If you modify attributes you will have to run\n`composer dump-autoload` to refresh the \"attributes\" file.\n\nAs a workaround you could have watchers on the directories that contain classes with attributes to\nrun `XDEBUG_MODE=off composer dump-autoload` when you make changes. [PhpStorm offers file\nwatchers][phpstorm-watchers]. You could also use [spatie/file-system-watcher][], it only requires\nPHP. If the plugin is too slow for your liking, try running the command with\n`COMPOSER_ATTRIBUTE_COLLECTOR_USE_CACHE=yes`, it will enable caching and speed up consecutive runs.\n\n\n\n----------\n\n\n\n## Continuous Integration\n\nThe project is continuously tested by [GitHub actions](https://github.com/olvlvl/composer-attribute-collector/actions).\n\n[![Tests](https://github.com/olvlvl/composer-attribute-collector/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/olvlvl/composer-attribute-collector/actions/workflows/test.yml)\n[![Static Analysis](https://github.com/olvlvl/composer-attribute-collector/actions/workflows/static-analysis.yml/badge.svg?branch=main)](https://github.com/olvlvl/composer-attribute-collector/actions/workflows/static-analysis.yml)\n[![Code Style](https://github.com/olvlvl/composer-attribute-collector/actions/workflows/code-style.yml/badge.svg?branch=main)](https://github.com/olvlvl/composer-attribute-collector/actions/workflows/code-style.yml)\n\n\n\n## Code of Conduct\n\nThis project adheres to a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in\nthis project and its community, you're expected to uphold this code.\n\n\n\n## Contributing\n\nSee [CONTRIBUTING](CONTRIBUTING.md) for details.\n\n\n\n[Composer]:  https://getcomposer.org/\n[root-only]: https://getcomposer.org/doc/04-schema.md#root-package\n[spatie/file-system-watcher]: https://github.com/spatie/file-system-watcher\n[phpstorm-watchers]: https://www.jetbrains.com/help/phpstorm/using-file-watchers.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folvlvl%2Fcomposer-attribute-collector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Folvlvl%2Fcomposer-attribute-collector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folvlvl%2Fcomposer-attribute-collector/lists"}