{"id":25228957,"url":"https://github.com/ajthinking/archetype","last_synced_at":"2025-05-16T05:04:45.696Z","repository":{"id":39802751,"uuid":"231596225","full_name":"ajthinking/archetype","owner":"ajthinking","description":"Edit PHP files programmatically","archived":false,"fork":false,"pushed_at":"2024-05-11T08:10:24.000Z","size":4316,"stargazers_count":260,"open_issues_count":2,"forks_count":19,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-09T04:20:15.240Z","etag":null,"topics":["composer-package","laravel","package","php","php-parser"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ajthinking.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"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":"2020-01-03T13:38:36.000Z","updated_at":"2025-05-02T13:59:28.000Z","dependencies_parsed_at":"2024-05-11T09:23:42.454Z","dependency_job_id":"79c0158a-b365-4902-a185-ee63a2d63540","html_url":"https://github.com/ajthinking/archetype","commit_stats":{"total_commits":1181,"total_committers":12,"mean_commits":98.41666666666667,"dds":"0.029635901778154117","last_synced_commit":"291f5d40c040829467c23bf4cf35d8acb4398daf"},"previous_names":[],"tags_count":42,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajthinking%2Farchetype","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajthinking%2Farchetype/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajthinking%2Farchetype/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajthinking%2Farchetype/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ajthinking","download_url":"https://codeload.github.com/ajthinking/archetype/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254471060,"owners_count":22076585,"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":["composer-package","laravel","package","php","php-parser"],"created_at":"2025-02-11T10:46:31.062Z","updated_at":"2025-05-16T05:04:45.677Z","avatar_url":"https://github.com/ajthinking.png","language":"PHP","funding_links":["https://github.com/sponsors/ajthinking"],"categories":[],"sub_categories":[],"readme":"![image](https://user-images.githubusercontent.com/3457668/148050728-f80fb02c-e24e-4957-b960-8e52796fbf23.png)\n\n### Enabling Rapid-Application-Development-tools, PR-bots, code analyzers and other things\n\n![tests](https://github.com/ajthinking/archetype/workflows/tests/badge.svg)\n![version](https://img.shields.io/packagist/v/ajthinking/archetype?color=blue)\n[![Total Downloads](https://img.shields.io/packagist/dt/ajthinking/archetype.svg)](https://packagist.org/packages/ajthinking/archetype)\n\n* Programatically modify php files with an intuitive top level read/write API\n* Read/write on classes, framework- and language constructs using `FileQueryBuilders` and `AbstractSyntaxTreeQueryBuilders`\n\n## Getting started\n```bash\ncomposer require ajthinking/archetype\n```\n\u003e \n\nThat's it! Check out introduction of concepts below or review the [API examples](docs.md)\n \n## `PHPFile` read/write API\n\n```php\nuse Archetype\\Facades\\PHPFile;\n\n// Create new files\nPHPFile::make()-\u003eclass(\\Acme\\Product::class)\n    -\u003euse('Shippable')\n    -\u003epublic()-\u003eproperty('stock', -1)\n    -\u003esave();\n```\n\n```php\n// Modify existing files  \nPHPFile::load(\\App\\Models\\User::class)\n    -\u003eclassName('NewClassName')\n    -\u003esave();\n```\n\n## `LaravelFile` read/write API\n\n```php example\nuse Archetype\\Facades\\LaravelFile; // extends PHPFile\n\n// Expanding on our User model\nLaravelFile::user()\n    -\u003eadd()-\u003euse(['App\\Traits\\Dumpable', 'App\\Contracts\\PlayerInterface'])\n    -\u003eadd()-\u003eimplements('PlayerInterface')\n    -\u003etable('gdpr_users')\n    -\u003eadd()-\u003efillable('nickname')\n    -\u003eremove()-\u003ehidden()\n    -\u003eempty()-\u003ecasts()\n    -\u003ehasMany('App\\Game')\n    -\u003ebelongsTo('App\\Guild')\n    -\u003esave()\n    -\u003erender();\n```\n\n\u003cdetails\u003e\u003csummary\u003eShow output\u003c/summary\u003e\n\n```php\n\u003c?php\n\nnamespace App\\Models;\n\nuse App\\Contracts\\PlayerInterface;\nuse App\\Traits\\Dumpable;\nuse Illuminate\\Contracts\\Auth\\MustVerifyEmail;\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Foundation\\Auth\\User as Authenticatable;\nuse Illuminate\\Notifications\\Notifiable;\nuse Laravel\\Sanctum\\HasApiTokens;\n\nclass User extends Authenticatable implements PlayerInterface\n{\n    use HasApiTokens, HasFactory, Notifiable;\n    protected $table = 'gdpr_users';\n\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array\u003cint, string\u003e\n     */\n    protected $fillable = [\n        'name',\n        'email',\n        'password',\n        'nickname',\n    ];\n\n    /**\n     * The attributes that should be cast.\n     *\n     * @var array\u003cstring, string\u003e\n     */\n    protected $casts = [];\n    \n    /**\n     * Get the associated Guild\n     */\n    public function guild()\n    {\n        return $this-\u003ebelongsTo(Guild::class);\n    }\n    \n    /**\n     * Get the associated Games\n     */\n    public function games()\n    {\n        return $this-\u003ehasMany(Game::class);\n    }\n}\n\n```\n\n\u003c/details\u003e\n\n## File QueryBuilders\nFilter and retrieve a set of files to interact with. \n\n```php\n// find files with the query builder\nPHPFile::in('database/migrations')\n    -\u003ewhere('extends', 'Migration')\n    -\u003eandWhere('className', 'like', 'Create')\n    -\u003eget() // returns Collection of PHPFiles\n\n// Quickly find the Laravel User file\n$file = LaravelFile::user();\n\n// Quickly find Laravel specific files\nLaravelFile::models()-\u003eget();\nLaravelFile::controllers()-\u003eget();\nLaravelFile::serviceProviders()-\u003eget();\n// ...\n```\n\n## Abstract Syntax Tree QueryBuilder\n\nAs seen in the previous examples we can query and manipulate nodes with simple or primitive values, such as *strings* and *arrays*. However, if we want to perform custom or more in dept queries we must use the `ASTQueryBuilder`.\n\nExample: how can we fetch explicit column names in a migration file?\n\n```php\nLaravelFile::load('database/migrations/2014_10_12_000000_create_users_table.php')\n    -\u003eastQuery() // get a ASTQueryBuilder\n    -\u003eclassMethod()\n    -\u003ewhere('name-\u003ename', 'up')\n    -\u003estaticCall()\n    -\u003ewhere('class', 'Schema')\n    -\u003ewhere('name-\u003ename', 'create')\n    -\u003eargs\n    -\u003eclosure()\n    -\u003estmts\n    -\u003emethodCall()\n    -\u003ewhere('var-\u003ename', 'table')\n    -\u003eargs\n    -\u003evalue\n    -\u003evalue\n    -\u003eget();\n```\n\nThe ASTQueryBuilder examines all possible paths and automatically terminates those that cant complete the query:\n\n\u003cimg src=\"https://user-images.githubusercontent.com/3457668/83963046-25785480-a8a3-11ea-9224-b04fa8cebb81.png\" width=\"600px\"\u003e\n\nThe ASTQueryBuilder relies entirely on [nikic/php-parser](https://github.com/nikic/php-parser). Available query methods mirror the `PhpParser` types and properties. To understand this syntax better you may want to tinker with `dd($file-\u003east())` while building your queries. Basic conventions are listed below. \n\n* Traverse into *nodes* by using methods (`method()`,`staticCall()` ...)\n* Traverse into *node properties* by accessing properties (`args`,`stmts` ...)    \n* Filter results with `where(...)`\n* Resolving matching paths with `get()`\n\n\u003e `ASTQueryBuilder` also supports *removing*, *replacing* and *injecting* nodes :wrench:\n\n```php\n// Replace a node property\n$file-\u003eastQuery()\n    -\u003eclass()\n    -\u003ename\n    -\u003ereplaceProperty('name', $newClassName)\n    -\u003ecommit() // updates the file's AST\n    -\u003eend() // exit query\n    -\u003esave() \n```\n\n## Errors 😵\nIf a file can't be parsed, a `FileParseError` will be thrown. This can happen if you try to explicitly load a broken file *but also* when performing queries matching one or more problematic files.\n\nTo see *all* offending files run `php artisan archetype:errors`. To ignore files with problems, put them in `config/archetype.php` -\u003e `ignored_paths`.\n\n## Configuration\n```bash\nphp artisan vendor:publish --provider=\"Archetype\\ServiceProvider\"\n```\n\n## Requirmenst\n* UNIX filesystem\n* PHP \u003e= 7.4\n* Laravel \u003e= 7\n\n## Contributing\nPRs and issues are welcome :pray: Feel free to take a stab at an [incomplete test](https://github.com/ajthinking/archetype/search?q=%24this-%3EmarkTestIncomplete).\n### Development installation\n```\ngit clone git@github.com:ajthinking/archetype.git\ncd archetype\ncomposer install\n./vendor/bin/pest\n```\n\n\n## License\nMIT\n\n\n## Acknowledgements\n* Built with [nikic/php-parser](https://github.com/nikic/php-parser)\n* PSR Printing fixes borrowed from [tcopestake/PHP-Parser-PSR-2-pretty-printer](https://github.com/tcopestake/PHP-Parser-PSR-2-pretty-printer)\n\n\n## Like this package?\n\u003ca href=\"https://github.com/ajthinking/archetype/stargazers\" \u003eStar it :star: \u003c/a\u003e\n\n[Say hi: @ajthinking :gem:](https://twitter.com/ajthinking)\n\n[Github Sponsors :octocat::heart:](https://github.com/sponsors/ajthinking)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fajthinking%2Farchetype","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fajthinking%2Farchetype","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fajthinking%2Farchetype/lists"}