{"id":15036715,"url":"https://github.com/imanghafoori1/laravel-microscope","last_synced_at":"2025-05-14T07:08:21.812Z","repository":{"id":38408461,"uuid":"247825643","full_name":"imanghafoori1/laravel-microscope","owner":"imanghafoori1","description":"Fearless refactoring, it does a lot of smart checks to find certain errors.","archived":false,"fork":false,"pushed_at":"2025-05-07T10:34:46.000Z","size":1808,"stargazers_count":1490,"open_issues_count":13,"forks_count":98,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-05-07T11:33:29.808Z","etag":null,"topics":["laravel"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/imanghafoori1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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-03-16T22:07:44.000Z","updated_at":"2025-05-07T10:31:35.000Z","dependencies_parsed_at":"2023-12-25T00:19:19.574Z","dependency_job_id":"9bda7308-a163-4519-9d55-56948a12f66a","html_url":"https://github.com/imanghafoori1/laravel-microscope","commit_stats":{"total_commits":1259,"total_committers":35,"mean_commits":35.97142857142857,"dds":"0.19380460683081813","last_synced_commit":"84583aa200ce82e5185921910cf3b1c59a3a429a"},"previous_names":[],"tags_count":376,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imanghafoori1%2Flaravel-microscope","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imanghafoori1%2Flaravel-microscope/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imanghafoori1%2Flaravel-microscope/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imanghafoori1%2Flaravel-microscope/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/imanghafoori1","download_url":"https://codeload.github.com/imanghafoori1/laravel-microscope/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254092659,"owners_count":22013290,"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":["laravel"],"created_at":"2024-09-24T20:32:06.410Z","updated_at":"2025-05-14T07:08:21.785Z","avatar_url":"https://github.com/imanghafoori1.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch2 align=\"center\"\u003e\n     Find Bugs Before They Bite\n\u003c/h2\u003e\n\n\n\u003cp align=\"center\"\u003e\n    \u003cimg width=\"300px\" src=\"https://user-images.githubusercontent.com/6961695/78522127-920e9e80-77e1-11ea-869a-05a29466e6b0.png\" alt=\"microscope_header\"\u003e\u003c/img\u003e\n\u003c/p\u003e\n\n\u003ch4 align=\"center\"\u003e\nBuilt with :heart: for lazy Laravel developers ;)\n\u003c/h4\u003e\n\n\u003ch3 align=\"center\"\u003e\nWhy repeat the old errors, if there are so many new errors to commit?\n\u003c/h3\u003e\n\u003ch3 align=\"center\"\u003e\n(Bertrand Russel)\n\u003c/h3\u003e\n\u003ch5 align=\"center\"\u003e\nGive your eyes a rest, we will detect and fix them for you.\n\u003c/h5\u003e\n\n![Packagist Stars](https://img.shields.io/packagist/stars/imanghafoori/laravel-microscope)\n[![Required Laravel Version][ico-laravel]][link-packagist]\n[![Required PHP Version][ico-php]][link-packagist]\n[![Latest Version on Packagist][ico-version]][link-packagist]\n[![Quality Score][ico-code-quality]][link-code-quality]\n[![Total Downloads][ico-downloads]][link-downloads]\n[![Today Downloads][ico-today-downloads]][link-downloads]\n[![tests](https://github.com/imanghafoori1/laravel-microscope/actions/workflows/run-tests.yml/badge.svg?branch=master)](https://github.com/imanghafoori1/laravel-microscope/actions/workflows/run-tests.yml)\n[![Imports](https://github.com/imanghafoori1/laravel-microscope/actions/workflows/imports.yml/badge.svg?branch=master)](https://github.com/imanghafoori1/laravel-microscope/actions/workflows/imports.yml)\n\n\u003c!--\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://packagist.org/packages/imanghafoori/laravel-microscope\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/8d75e05f4b67de65b51e10772b054f506aa8cfab/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f696d616e676861666f6f72692f6c61726176656c2d6d6963726f73636f70652e7376673f7374796c653d666c61742d737175617265\" alt=\"Latest Version on Packagist\" data-canonical-src=\"https://img.shields.io/packagist/v/imanghafoori/laravel-microscope.svg?style=round-square\" style=\"max-width:100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"https://travis-ci.org/imanghafoori1/laravel-self-test\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/63b18ae839896de4604ede21595326389fed0b1f/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f696d616e676861666f6f7269312f6c61726176656c2d73656c662d746573742f6d61737465722e7376673f7374796c653d666c61742d737175617265\" alt=\"Build Status\" data-canonical-src=\"https://img.shields.io/travis/imanghafoori1/laravel-self-test/master.svg?style=round-square\" style=\"max-width:100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"https://scrutinizer-ci.com/g/imanghafoori1/laravel-microscope\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/ee6d1b9eee22268201b7e253867c6bb64838651e/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f672f696d616e676861666f6f7269312f6c61726176656c2d6d6963726f73636f70652e7376673f7374796c653d666c61742d737175617265\" alt=\"Quality Score\" data-canonical-src=\"https://img.shields.io/scrutinizer/g/imanghafoori1/laravel-microscope.svg?style=round-square\" style=\"max-width:100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"https://packagist.org/packages/imanghafoori/laravel-microscope\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/5441e915afbdb81de92b808965f294b0c7d18c52/68747470733a2f2f706f7365722e707567782e6f72672f696d616e676861666f6f72692f6c61726176656c2d6d6963726f73636f70652f642f6461696c79\" alt=\"Daily Downloads\" data-canonical-src=\"https://poser.pugx.org/imanghafoori/laravel-microscope/d/daily\" style=\"max-width:100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"https://packagist.org/packages/imanghafoori/laravel-microscope\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/7f10826df8cf3fb52525fd2494554c0e587b8bb7/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f696d616e676861666f6f72692f6c61726176656c2d6d6963726f73636f70652e7376673f7374796c653d666c61742d737175617265\" alt=\"Total Downloads\" data-canonical-src=\"https://img.shields.io/packagist/dt/imanghafoori/laravel-microscope.svg?style=round-square\" style=\"max-width:100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"/imanghafoori1/laravel-microscope/blob/master/LICENSE.md\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/d885b3999bb863974fb67118174bb0402d089a89/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e7376673f7374796c653d726f756e642d737175617265\" alt=\"Software License\" data-canonical-src=\"https://img.shields.io/badge/license-MIT-blue.svg?style=round-square\" style=\"max-width:100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n--\u003e\n\n- Table Of Contents\n    - [Key Things To Know](#key-things-to-know)\n    - [Installation](#installation)\n    - [Usage](#usage)\n        - [Useful Commands](#useful-commands)\n        - [Fewer Use Commands](#less-use-commands)\n        - [Global Helper Functions](#global-helper-functions)\n    - [What The Commands Do?](#what-the-commands-do)\n\n      \u003cdetails\u003e\n\n        \u003csummary\u003eshow commands\u003c/summary\u003e\n\n        1. [`php artisan search_replace`](#search_replace)\n            - [Defining Patterns](#defining-patterns)\n            - [Placeholders](#placeholders)\n            - [Mutator](#mutator)\n            - [Filters](#filters)\n            - [Capturing Php \"statements\"](#capturing-php-statements)\n            - [Capturing Global Function Calls](#capturing-global)\n            - [Repeating Patterns](#repeating-patterns)\n\n        1. [`php artisan check:early_returns`](#early_returns)\n        1. [`php artisan check:psr4`](#psr4)\n        1. [`php artisan check:generate`](#generate)\n        1. [`php artisan check:imports`](#imports)\n        1. [`php artisan check:bad_practices`](#bad_practices)\n        1. [`php artisan check:routes`](#routes)\n        1. [`php artisan check:compact`](#compact)\n        1. [`php artisan check:blade_queries`](#blade_queries)\n        1. [`php artisan check:extract_blades`](#extract_blades)\n        1. [`php artisan check:action_comments`](#action_comments)\n        1. [`php artisan pp:route`](#route)\n        1. [`php artisan check:views`](#views)\n        1. [`php artisan check:events`](#events)\n        1. [`php artisan check:gates`](#gates)\n        1. [`php artisan check:aliases`](#aliases)\n        1. [`php artisan check:dead_controllers`](#dead_controllers)\n        1. [`php artisan check:generic_docblocks`](#generic_docblocks)\n        1. [`php artisan check:migrations`](#migrations)\n        1. [`php artisan check:empty_comment`](#empty_comment)\n        1. [`php artisan enforce:helper_functions`](#helper_functions)\n        1. [`php artisan list:models`](#models)\n    \n     \u003c/details\u003e\n\n    - [Credits](#credits)\n    - [License](#license)\n    - [Contributing](#contributing)\n    - [More From The Author](#more-from-author)\n    - [Contributors](#contributors)\n\n\u003ca name=\"key-things-to-know\"\u003e\u003c/a\u003e\n## Key things to know:\n\n- It is created to be **smarter than phpstorm** and other IDEs in finding errors.\n- It is created to **understand laravel run-time** and magic.\n- It does **not show you stupid false errors**, all the reported cases are really errors.\n- Even If you have written a lot of tests for your app, **you may still need this**.\n- **It can refactor your code**, by applying `early returns` automatically.\n- It is written from scratch to yield the **maximum performance** possible.\n\n### :film_strip: Video tutorial [here](https://youtu.be/aEkiE30wNKk)\n\n### :star: Your Stars Make Us Do More\n\u003eIf you found this package useful, and you want to encourage the maintainer to work on it, just press the star button to declare your willingness.\n\n\u003ca href=\"https://github.com/imanghafoori1/microscope/stargazers\"\u003eStargazers\u003c/a\u003e\n\n\u003ca name=\"installation\"\u003e\u003c/a\u003e\n## \u003cg-emoji class=\"g-emoji\" alias=\"arrow_down\" fallback-src=\"https://github.githubassets.com/images/icons/emoji/unicode/2b07.png\"\u003e⬇️\u003c/g-emoji\u003e Installation\n\nYou can **install** the package via Composer:\n\n```bash\ncomposer require imanghafoori/laravel-microscope --dev\n```\n\nYou may also **publish** config file:\n```\nphp artisan vendor:publish --provider=\"Imanghafoori\\LaravelMicroscope\\LaravelMicroscopeServiceProvider\"\n```\n\n\u003ca name=\"usage\"\u003e\u003c/a\u003e\n## \u003cg-emoji class=\"g-emoji\" alias=\"gem\" fallback-src=\"https://github.githubassets.com/images/icons/emoji/unicode/1f48e.png\"\u003e💎\u003c/g-emoji\u003e Usage:\n\n### Useful Commands:\n\n\n\u003eYou can run :point_down:\n\n|#|Artisan Command|\n|---|---|\n|1|`php artisan search_replace`|\n|2|`php artisan check:early_returns`|\n|3|`php artisan check:all`|\n\n\n\u003ca name=\"less-use-commands\"\u003e\u003c/a\u003e\n### Less Used Commands:\n\n|#|Artisan Command|\n|---|---|\n|1|`php artisan check:views`|\n|2|`php artisan check:routes`|\n|3|`php artisan check:psr4 {-s\\|--nofix} `|\n|4|`php artisan check:imports {-s\\|--nofix} {--wrong} {--extra}`|\n|5|`php artisan check:stringy_classes`|\n|6|`php artisan check:dd`|\n|7|`php artisan check:bad_practices`|\n|8|`php artisan check:compact`|\n|9|`php artisan check:blade_queries`|\n|10|`php artisan check:action_comments`|\n|11|`php artisan check:extract_blades`|\n|12|`php artisan pp:route`|\n|13|`php artisan check:generate`|\n|14|`php artisan check:endif`|\n|15|`php artisan check:events`|\n|16|`php artisan check:gates`|\n|17|`php artisan check:dynamic_where`|\n|18|`php artisan check:aliases`|\n|19|`php artisan check:dead_controllers`|\n|20|`php artisan check:generic_docblocks`|\n|21|`php artisan enforce:helper_functions`|\n|22|`php artisan list:models`|\n\n\u003ca name=\"global-helper-functions\"\u003e\u003c/a\u003e\n## Global Helper Functions:\n\u003eAlso, You will have access to some global helper functions\n\n```php \nmicroscope_dd_listeners($event);\n ```\nIn case you wonder what the listeners are and where they are,\nyou can call `microscope_dd_listeners(MyEvent::class);` within either the `boot` or `register` methods.\nIt works like a normal `dd(...);` meaning that the program stops running at that point.\n\n\u003ca name=\"what-the-commands-do\"\u003e\u003c/a\u003e\n## \u003cg-emoji class=\"g-emoji\" alias=\"book\" fallback-src=\"https://github.githubassets.com/images/icons/emoji/unicode/1f4d6.png\"\u003e📖\u003c/g-emoji\u003e What do the Commands do?\n\nLet's start with the:\n\n\u003ca name=\"search_replace\"\u003e\u003c/a\u003e\n### `php artisan search_replace {--name=pattern_name} {--tag=some_tag} {--file=partial_file_name} {--folder=partial_folder_name}`\n\nThis is a smart and very powerful search/replace functionality that can be a real \"time saver\" for you.\n\n\u003ca name=\"defining-patterns\" \u003e\u003c/a\u003e\n#### :one:\t\tDefining patterns:\n\n\u003eIf you run the command `artisan search_replace` for the first time, it will create a `search_replace.php` file in the project's root.\nThen, you can define your patterns, within that file.\n\n\n**Examples:**\n\nLet's define a pattern to replace the `optional()` global helper with the `?-\u003e` php 8 null safe operator:\n\n```php\nreturn [\n    'optional_to_nullsafe' =\u003e [\n        'search' =\u003e '\"\u003cglobal_func_call:optional\u003e\"(\"\u003cin_between\u003e\")-\u003e',\n        'replace' =\u003e '\"\u003c2\u003e\"?-\u003e',\n        // 'tag' =\u003e 'php8,refactor',\n        // 'predicate' =\u003e function($matches, $tokens) {...},\n        // 'mutator' =\u003e function($matches) {...},\n        // 'post_replace' =\u003e [...],\n        // 'avoid_result_in' =\u003e [...],\n        // 'avoid_syntax_errors' =\u003e false,\n        // 'filters' =\u003e [...],\n    ]\n];\n```\n- Here the key `optional_to_nullsafe` is the \"unique name\" of your pattern. (You can target your pattern by running ```php artisan search_replace --name=optional_to_nullsafe```)\n- The search pattern has a `\"\u003cin_between\u003e\"` placeholder which captures everything in between the pair of parenthesis.\n- In the `replace` block we substitute what we have captured by the first placeholder with the `\"\u003c1\u003e\"`.\n  If we have more placeholders, we could have had `\"\u003c2\u003e\"` etc.\n- In the tag block we can mention some tags as an array of strings or a string separated by commas\n  and target them by `--tag` flag: ```php artisan search_replace --tag=php8```\n\n\u003ca name=\"placeholders\" \u003e\u003c/a\u003e\n:two: **Placeholders:**\n\nHere is a comprehensive list of placeholders you can use:\n\n|#|Placeholders|Description|\n|---|---|---|\n|1|`\u003cvar\u003e` or `\u003cvariable\u003e`|for variables like: `$user`|\n|2|`\u003cstr\u003e` or `\u003cstring\u003e`|for hard coded strings: `'hello'` or \"hello\"|\n|3|`\u003cclass_ref\u003e`|for class references:  `\\App\\User::where(...` , `User::where`|\n|4|`\u003cfull_class_ref\u003e`|only for full references:  `\\App\\User::`|\n|5|`\u003cuntil\u003e`|to capture all the code until you reach a certain character.|\n|6|`\u003ccomment\u003e`|for comments (it does not capture doc-blocks beginning with: /** )|\n|7|`\u003cdoc_block\u003e`|for php doc-blocks|\n|8|`\u003cstatement\u003e`|to capture a whole php statement.|\n|9|`\u003cname:nam1,nam2\u003e` or `\u003cname\u003e`|for method or function names. `-\u003ewhere` or `::where`|\n|10|`\u003cwhite_space\u003e`|for whitespace blocks|\n|11|`\u003cbool\u003e` or `\u003cboolean\u003e`|for true or false (acts case-insensitive)|\n|12|`\u003cnumber\u003e`|for numeric values|\n|13|`\u003ccast\u003e`|for type-casts like: `(array) $a;`|\n|14|`\u003cint\u003e` or `\"\u003cinteger\u003e\"`|for integer values|\n|15|`\u003cvisibility\u003e`|for public, protected, private|\n|16|`\u003cfloat\u003e`|for floating point number|\n|17|`\"\u003cglobal_func_call:func1,func2\u003e\"`|to detect global function calls|\n|18|`\u003cin_between\u003e`|to capture code within a pair of  `{...}` or `(...)` or `[...]`|\n|19|`\u003cany\u003e`|captures any token.|\n\n\u003eYou can also define your own keywords if needed!\n\u003e\n\u003eYou just define a class for your new keyword and append the classpath to the end of the `Finder::$keywords[] = MyKeyword::class` property.\nJust like the default keywords.\n\n**Example:**\n\n:one:  Let's say you want to find only the \"comments\" that contain the word \"todo:\" in them.\n```php\n 'todo_comments' =\u003e [\n        'search' =\u003e '\u003ccomment\u003e',\n        'predicate' =\u003e function($matches) {    //   \u003c====  here we check comment has \"todo:\"\n            $comment = $matches[0]; // first placeholder value\n            $content = $comment[1]; // get its content\n            \n            return Str::contains($content, 'todo:') ? true : false;\n        },\n]\n\n```\n\n_Note_ If you do not mention the `'replace'` key it only searches and reports them to you.\n\n:two: Ok, now let's say you want to remove the \"todo:\" word from your comments:\n\n```php\n 'remove_todo_comments' =\u003e [\n    'search' =\u003e '\u003ccomment\u003e',      //   \u003c=== we capture any comment\n    'replace' =\u003e '\u003c1\u003e',\n\n    'predicate' =\u003e function($matches) {\n        $comment = $matches[0]; // first matched placeholder\n        $content = $comment[1];\n\n        return Str::contains($content, 'todo:') ? true : false;\n    },\n\n    'mutator' =\u003e function ($matches) {       //  \u003c=== here we remove \"todo:\"\n        $matches[0][1] = str_replace('todo:', '', $matches[0][1]);\n\n        return $matches;\n    }\n]\n\n```\nConverts: ``` // todo: refactor code```\nInto: ``` // refactor code```\n\n\u003ca name=\"mutator\" \u003e\u003c/a\u003e\n:three: **Mutator:**\nIn mutators, you are free to manipulate the `$matched` values as much as you need to before replacing them in the results.\nYou can also mention a static method instead of a function, like this: `[MyClass::class, 'myStaticMethod']`\n\n\n:three: Let's say you want to put the optional comma for the Lets  elements in the arrays if they are missing.\n```php\n    'enforce_optional_comma' =\u003e [\n        'search' =\u003e '\u003cwhite_space\u003e?]',\n        'replace' =\u003e ',\"\u003c1\u003e\"]',\n        'avoid_syntax_errors' =\u003e true,\n        'avoid_result_in' =\u003e [\n           ',,]',\n           '[,]',\n           '\u003cvar\u003e[,]'\n       ],\n    ]\n```\nIn this case, our pattern is not very accurate and in some cases, it may result in syntax errors.\nBecause of  that, we turn on the php syntax validator to check the result, but that costs us a performance penalty!!!\nTo exclude the usage of PHP, to validate the results we have mentioned the `avoid_result_in` so that if they happen in the result it skips.\n\n- **Note**: The `?` in the \"\u003cwhite_space\u003e?\" notes this is an `optional` placeholder.\n\nIf you are curious to see a better pattern that does not need any syntax checking, try this:\n\n```\n'enforce_optional_comma' =\u003e [\n       'search' =\u003e '\u003c1:any\u003e\u003c2:white_space\u003e?[\u003c3:until_match\u003e]',\n       'replace' =\u003e '\u003c1\u003e\u003c2\u003e[\u003c3\u003e,]',\n       'avoid_result_in' =\u003e [\n           ',,]',\n           '[,]'\n       ],\n       'predicate' =\u003e function ($matches) {\n           $type = $matches['values'][0][0];\n\n           return $type !== T_VARIABLE \u0026\u0026 $type !== ']';\n       },\n       'post_replace' =\u003e [\n           '\u003c1:white_space\u003e,]' =\u003e ',\u003c1\u003e]'\n       ]\n],\n\n```\nThis is more complex but works much faster. (since it does not need the php syntax validator)\n\n- Here `'post_replace'` is a pattern that is applied only and only on the resulting code to refine it, and NOT on the entire file.\n\n- You can optionally comment your placeholders (as above `\u003c1:any\u003e`) with numbers so that you know which one corresponds to which when replaced.\n\n\u003ca name=\"filters\" \u003e\u003c/a\u003e\n:four: **Filters:**\n\nCurrently, the microscope offers only two built-in filters: `is_sub_class_of` and `in_array`\n\nCan you guess what the heck this pattern is doing?!\n```php\n 'mention_query' =\u003e [\n      'search' =\u003e '\u003c1:class_ref\u003e::\u003c2:name\u003e'\n      'replace' =\u003e '\u003c1\u003e::query()-\u003e\u003c2\u003e',\n      'filters' =\u003e [\n          1 =\u003e [\n              'is_sub_class_of' =\u003e \\Illuminate\\Database\\Eloquent\\Model::class\n          ],\n          2 =\u003e [\n              'in_array' =\u003e 'where,count,find,findOrFail,findOrNew'\n          ]\n      ]\n  ]\n```\n\n\nIt converts these:\n```php\nUser::where(...)-\u003eget();\n\n\\App\\Models\\User::find(...);\n```\n\nInto these:\n```php\nUser::query()-\u003ewhere(...)-\u003eget();\n\n\\App\\Models\\User::query()-\u003efind(...);\n```\n\n- The filters here ensure that the captured class reference is a Laravel Model and the method name is one of the names mentioned in the list.\n\nSo it does not tamper with something like this:\n```php\nUser::all();            // The `all` method can not be preceded by `query`\n\nUserRepo::where(...);   /// UserRepo is not a model\n```\n\n- This is something that you can never do by regex.\n\n\u003ca name=\"capturing-php-statements\" \u003e\u003c/a\u003e\n:five: **Capturing php \"statements\":**\n\nLet's say we want to opt into PHP v7.4 arrow functions:\n\n```php\n'fn' =\u003e [\n    'search' =\u003e 'function (\u003cin_between\u003e)\u003cuntil\u003e{ return \u003cstatement\u003e; }',\n    'replace' =\u003e 'fn (\u003c1\u003e) =\u003e \u003c3\u003e',\n    'tags' =\u003e 'php74,refactor',\n]\n\n```\n\nIn this example, we have mentioned one single \"statement\" in the body of the function.\nSo if it encounters a function with two or more statements it will ignore that.\n\n```php\n$closure = function ($a) use ($b) {\n    return $a + $b;\n};\n\n// will become:\n$closure = fn($a) =\u003e $a + $hello;\n```\n\nBut this is not captured:\n```php\n$closure = function ($a) {\n    $a++;\n    return $a + $b;\n};\n```\n\n:six: **Difference between `\u003cstatement\u003e` and `\u003cuntil\u003e;`**\n\nThey seem to be very similar but there is an important case in which you can not use `\u003cuntil\u003e;` to cover it properly!\n\n```php\n$first = $a + $b;\n\n$second = function ($a) {\n    $a++;\n\n    return $a;\n};\n```\n\nIf we define our pattern like this:\n\n```php\nreturn [\n    'pattern_name' =\u003e [\n        'search' =\u003e '\u003cvar\u003e = \u003cuntil\u003e;',   \n    ]\n];\n```\nFor `$c = $a + $b;` they act the same way, but for the second one `\"\u003cuntil\u003e\";` will not capture the whole closure and will stop as soon as it reaches `$a++;` and that is a problem.\n\nBut if you define your pattern as: `'\u003cvar\u003e = \u003cstatement\u003e'` it would be smart enough to capture the correct semicolon at the end of the closure definition and the whole close would be captured.\n\n\u003ca name=\"capturing-global\" \u003e\u003c/a\u003e\n:seven: **Capturing global function calls:**\n\nLet's say you want to eliminate all the `dd(...)` or `dump(...)` before pushing to production.\n```php\nreturn [\n    'remove_dd' =\u003e [\n        'search' =\u003e  \"'\u003cglobal_func_call:dd,dump\u003e'('\u003cin_between\u003e');\", \n        'replace' =\u003e ''\n    ]\n];\n```\n\nThis will NOT capture cases like below:\n```php\n$this-\u003e  dd('hello');          // is technically a method call\nUser::   dd('I am static');    // is technically a static method call\nnew      dd('I am a class');  // here \"dd\" is the name of a class.\n   \n```\n\nBut will detect and remove real global `dd()` calls with whatever parameters they have received.\n\n```\ndd(                // \u003c=== will be detected, even if the pattern above is written all in one line.\n   auth('admin')\n        -\u003euser()-\u003eid   \n);\n    \n    \n\\dd(1);\ndd(1);\ndump(1);\n    \n```\n\u003ca name=\"repeating-patterns\" \u003e\u003c/a\u003e\n:eight: **Repeating patterns:**\n\nLet's say we want to refactor:\n```php\nUser:where('name', 'John')-\u003ewhere('family', 'Dou')-\u003ewhere('age', 20)-\u003eget();\n```\n\ninto:\n```php\nUser:where([\n    'name' =\u003e 'John',\n    'family' =\u003e 'Dou',\n    'age'=\u003e 20,\n])-\u003eget();\n```\n\nOk, how the pattern would look like then?!\n\n```php\n\"group_wheres\" =\u003e [\n       \n       'search' =\u003e '\u003c1:class_ref\u003e::where('\u003c2:str\u003e', '\u003c3:str\u003e')'\u003crepeating:wheres\u003e'-\u003eget();'\n       \n       'replace' =\u003e '\u003c1\u003e::where([\n           \u003c2\u003e =\u003e \u003c3\u003e,\n           \"\u003crepeating:1:key_values\u003e\"])-\u003eget();',\n\n       'named_patterns' =\u003e [\n           'wheres' =\u003e '-\u003ewhere(\u003cstr\u003e, \u003cstr\u003e)\u003cwhite_space\u003e?',\n           'key_values' =\u003e '\u003c1\u003e =\u003e \u003c2\u003e,\u003c3\u003e',\n       ]\n   ]\n```\n\nNice yeah??!\n\n\u003ePossibilities are endless and the sky is the limit...\n\n\n\n\n\u003ca name=\"early_returns\"\u003e\u003c/a\u003e\n### `php artisan check:early_returns`\n\n\nThis will scan all your Psr-4 loaded classes and flattens your functions and loops by applying the early return rule.\nFor example:\n\n```php\n\u003c?php\n\nforeach ($products as $product) {\n    if ($someCond) {\n        // A lot of code 1\n        // A lot of code 1\n        // A lot of code 1\n        // A lot of code 1\n        // A lot of code 1\n        if ($someOtherCond) {\n            // A lot more code 2\n            // A lot more code 2\n            // A lot more code 2\n            // A lot more code 2 \n            // A lot more code 2\n            //\n        } // \u003c--- closes second if\n    } // \u003c--- closes first if\n}\n\n```\n\nWill be discovered and converted into:\n\n```php\n\u003c?php\n\nforeach ($products as $product) {\n    if (! $someCond) {\n        continue;\n    }\n    \n    // A lot of code 1\n    // A lot of code 1\n    // A lot of code 1\n    // A lot of code 1\n    // A lot of code 1\n\n    if (! $someOtherCond) {\n        continue;\n    }\n \n    // A lot more code 2\n    // A lot more code 2\n    // A lot more code 2\n    // A lot more code 2 \n    // A lot more code 2\n}\n\n```\n\nThe same thing will apply for functions and methods, but with `return`\n\n```php\n\u003c?php\n\nif ($cond1) {\n    if ($cond2) {\n        ....       \n    }\n}\n\n// we get merged into:\n\nif ($cond1 \u0026\u0026 $cond2) { \n    ...  \n}\n\n```\n\n- It also supports the ruby-like if():/endif; syntax;\n\n```php\n\u003c?php\n\nif ($var1 \u003e 1):\n    if ($var2 \u003e 2):\n        echo 'Hey Man';\n    endif;\nendif;\n\n// Or if you avoid putting curly braces...\nif ($var1 \u003e 1)\n    if ($var2 \u003e 2)\n        echo 'Hey Man';\n\n```\n\n**Although this type of refactoring is safe and is guaranteed to do the same thing as before, be careful to commit everything before trying this feature, in case of a weird bug or something.**\n\n\n\u003ca name=\"psr4\"\u003e\u003c/a\u003e\n### `php artisan check:psr4`\n\n- It checks for all the psr4 autoload defined in the composer.json file and goes through all the classes to have the right namespace, according to PSR-4 standard.\n- It automatically corrects namespaces (according to PSR-4 rules)\n- It also checks for references to the old namespace with the system and replaces them with the new one.\n\n\n\u003ca name=\"generate\"\u003e\u003c/a\u003e\n\n### `php artisan check:generate`\n\nYou make an empty file, and we fill it, based on naming conventions.\n\nIf you create an empty `.php` file which ends with `ServiceProvider.php` after running this command: \u003c/br\u003e\n- It will be filled with a boilerplate and correct Psr-4 namespace. \u003c/br\u003e\n- It will be appended to the `providers` array in the `config/app.php`\n\n\n\u003ca name=\"imports\"\u003e\u003c/a\u003e\n\n### `php artisan check:imports`\n\n\n- It checks all the imports (`use` statements) to be valid and reports invalid ones.\n- It autocorrects some references, no ambiguity is around the class name.\n- It can understand the laravel aliased classes so `use Request;` would be valid.\n\n\n\u003ca name=\"bad_practices\"\u003e\u003c/a\u003e\n\n### `php artisan check:bad_practices`\n\n\n- It detects bad practices like `env()` calls outside the config files.\n\n\u003ca name=\"routes\"\u003e\u003c/a\u003e\n\n### `php artisan check:routes`\n\n\n- It checks that your routes refer to valid controller classes and methods.\n- It checks all the controller methods to have valid type-hints.\n- It scans for `route()`, `redirect()-\u003eroute()`, `\\Redirect::route()` to refer to valid routes.\n- It will report the public methods of controllers, which have no routes pointing to them. In other words `dead controllers` are detected.\n\n\u003ca name=\"compact\"\u003e\u003c/a\u003e\n\n### `php artisan check:compact`\n\n\n- In php 7.3 if you \"compact\" a non-existent variable you will get an error, so this command checks the entire project for wrong `compact()` calls and reports to you, which parameters should be removed.\n\n\u003ca name=\"blade_queries\"\u003e\u003c/a\u003e\n\n### `php artisan check:blade_queries`\n\n- Blade files should not contain DB queries. We should move them back into controllers and pass variables.\nThis command searches all the blade files for the `Eloquent models` and `DB` query builder and shows them if any.\n\n\u003ca name=\"extract_blades\"\u003e\u003c/a\u003e\n### `php artisan check:extract_blades`\n\n\n- If you want to extract a blade partial out and make it included like: `@include('myPartials.someFile')`\n\nYou can use `{!! extractBlade('myPartials.someFile') !!}` in your blade files to indicate `start/end line` and the `path/name` of the partial you intend to be made.\n\n```html\n \u003chtml\u003e\n      \n      {!! extractBlade('myPartials.head') !!}\n          \u003chead\u003e...\u003c/head\u003e\n      {!! extractBlade() !!}\n\n      \n      {!! extractBlade('myPartials.body') !!}\n          \u003cbody\u003e...\u003c/body\u003e\n      {!! extractBlade() !!}\n      \n \u003c/html\u003e\n```\n\nAfter you execute `php artisan check:extract_blades` it will become:\n\n```html\n\u003chtml\u003e\n    @include('myPartials.head')\n    @include('myPartials.body')\n\u003c/html\u003e\n```\nAlso, it will create:\n- `resources/views/myPartials/head.blade.php`\n- `resources/views/myPartials/body.blade.php`\n\nAnd put the corresponding content in them.\n\n- It is also compatible with namespaced views in modular Laravel applications.\nSo this syntax will work: `'MyMod::myPartials.body'`\n\n\u003ca name=\"action_comments\"\u003e\u003c/a\u003e\n### `php artisan check:action_comments {--file=SomeFile.php}`\n\n\n- This adds annotations in the controller actions so that you know which route is pointing to the current controller action.\n- You can use the `--file=` option to narrow down the scanned files.\n\n\u003ca name=\"route\"\u003e\u003c/a\u003e\n### `php artisan pp:route`\n\n\n- First, you have to put this in your route file: `microscope_pretty_print_route('my.route.name');` \n- You can also pass the Controller@method syntax to the function.\n- You can call it multiple times to pretty-print multiple routes.\n\n\u003ca name=\"views\"\u003e\u003c/a\u003e\n### `php artisan check:views`\n\n\n- It scans your code and finds the `view()` and `View::make()` and reports if they refer to the wrong files.\n- It scans your blade files for `@include()` and `@extends()` and reports if they refer to the wrong files.\n\n\nAlso, it can detect `unused variables` which are passed into your view from the controller like this: `view('hello', [...]);`\nFor that you must open up the page in the browser and then visit the log file to see a message like this:\n```\nlocal.INFO: Laravel Microscope: The view file: welcome.index-1 at App\\Http\\Controllers\\HomeController@index has some unused variables passed to it:   \nlocal.INFO: array ('$var1' , '$var2');\n```\n\nRemember some variables are passed into your view from a `view composer` and not the controller.\nThose variables are also taken into consideration when detecting unused variables.\n\n\u003ca name=\"events\"\u003e\u003c/a\u003e\n### `php artisan check:events`\n\n\nFor example, consider:\n\n```php\nEvent::listen(MyEvent::class, '\\App\\Listeners\\MyListener@myMethod');\n```\n\n1 - It checks the `\\App\\Listeners\\MyListener` classpath to be valid.\n\n2 - It checks the `myMethod` method to exist on the `MyListener` class\n\n3 - It checks the `myMethod` method to have the right type-hint (if any) in its signature, for example:\n```php\npublic function myMethod(OtherEvent $e) // \u003c---- notice type-hint here\n{\n    //\n}\n```\nThis is a valid but wrong type-hint, and will be reported to you. Very cool, isn't it ??!\n\n\n- Note that it does not matter how you are setting your event listener, \n\n1- in the `EventServiceProvider`, \n\n2- By `Event::listen` facade, \n\n3- By Subscriber class... or any other way. The error would be found. :)\n\n\n\u003ca name=\"gates\"\u003e\u003c/a\u003e\n### `php artisan check:gates`\n\n\nIt checks the validity of all the gates you have defined, making sure that they refer to a valid class and method.\n\nIt also checks for the policy definitions to be valid.\n\n```php\nGate::policy(User::class, 'UserPolicy@someMethod');\nGate::define('someAbility', 'UserGate@someMethod');\n```\n\n1 - It checks the `User` classpath to be valid.\n\n2 - It checks the `UserPolicy` classpath to be valid.\n\n3 - It checks the `someMethod` method to exist.\n\n\u003ca name=\"dynamic_where\"\u003e\u003c/a\u003e\n\n### `php artisan check:dynamic_where`\n\n\n- It looks for \"dynamic where\" methods like `whereFamilyName('...')` with `where('family_name', '...')`.\n\n\u003ca name=\"enforce:query\"\u003e\u003c/a\u003e\n\n### `php artisan enforce:query`\n\n\n- It calls the static `query` method on your eloquent query chains so that IDEs can understand eloquent.\n\n- For example, converts: `User::where(...` to `User::query()-\u003ewhere(...`\n\n\u003ca name=\"dead_controllers\"\u003e\u003c/a\u003e\n\n### `php artisan check:dead_controllers`\n\n\n- We can find the controllers that don't have any routes.\n\n\u003ca name=\"generic_docblocks\"\u003e\u003c/a\u003e\n\n### `php artisan check:generic_docblocks {--folder=app/Models} {--file=SomeFile.php}`\n\n\n- Removes Laravel's DocBlocks.\n- You can use `--folder=` or `--file=` option to narrow down the scanned folders.\n\n\u003ca name=\"helper_functions\"\u003e\u003c/a\u003e\n\n### `php artisan enforce:helper_functions {--folder=app/Models} {--file=SomeFile.php}`               \n\n\n- Converting Laravel facade into helper functions.\n- You can use `--folder=` or `--file=` option to narrow down the scanned folders.\n\n\u003ca name=\"models\"\u003e\u003c/a\u003e\n\n### `php artisan list:models {--folder=app/Models}`               \n\n\n- It searches the project and lists the model classes.\n- You can use `--folder=` option to narrow down the scanned folders.\n\n\nAnd more features will be added soon. ;)\n\n\u003ca name=\"credits\"\u003e\u003c/a\u003e\n## Credits\n\n- [Iman](https://github.com/imanghafoori1)\n- [All Contributors](../../contributors)\n\n\u003ca name=\"license\"\u003e\u003c/a\u003e\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n\n\n\u003ca name=\"contributing\"\u003e\u003c/a\u003e\n\n### :raising_hand: Contributing\nIf you find an issue or have a better way to do something, feel free to open an issue or a pull request.\nIf you use laravel-microscope in your open source project, create a pull request to provide its URL as a sample application in the README.md file.\n\n\u003ca name=\"security\"\u003e\u003c/a\u003e\n### :exclamation: Security\nIf you discover any security-related issues, please email `imanghafoori1@gmail.com` instead of using the issue tracker.\n\n\u003ca name=\"more-from-author\"\u003e\u003c/a\u003e\n## More from the author:\n\n### Laravel HeyMan\n\n:gem: It allows us to write expressive code to authorize, validate, and authenticate.\n\n- https://github.com/imanghafoori1/laravel-heyman\n\n\n--------------\n\n### Laravel Terminator\n\n\n :gem: A minimal yet powerful package which allows you to refactor your controllers.\n\n- https://github.com/imanghafoori1/laravel-terminator\n\n\n\n### Laravel AnyPass\n\n:gem: It allows you to login with any password in the local environment only.\n\n- https://github.com/imanghafoori1/laravel-anypass\n\n\n\n```\nA man will never fail unless he stops trying.\n\nAlbert Einstein\n```\n\n[ico-laravel]: https://img.shields.io/badge/Laravel-%E2%89%A5%205.6-ff2d20?style=flat-square\u0026logo=laravel\n[ico-php]: https://img.shields.io/packagist/php-v/imanghafoori/laravel-microscope?color=%238892BF\u0026style=flat-square\u0026logo=php\n[ico-version]: https://img.shields.io/packagist/v/imanghafoori/laravel-microscope.svg?style=flat-square\n[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square\n[ico-travis]: https://img.shields.io/travis/imanghafoori1/laravel-self-test/master.svg?style=flat-square\u0026logo=travis\n[ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/imanghafoori1/laravel-microscope.svg?style=flat-square\u0026logo=scrutinizer\n[ico-code-quality]: https://img.shields.io/scrutinizer/g/imanghafoori1/laravel-microscope.svg?style=flat-square\u0026logo=scrutinizer\n[ico-downloads]: https://img.shields.io/packagist/dt/imanghafoori/laravel-microscope.svg?style=flat-square\n[ico-today-downloads]: https://img.shields.io/packagist/dd/imanghafoori/laravel-microscope.svg?style=flat-square\n\n[link-packagist]: https://packagist.org/packages/imanghafoori/laravel-microscope\n[link-travis]: https://travis-ci.org/imanghafoori1/laravel-self-test\n[link-scrutinizer]: https://scrutinizer-ci.com/g/imanghafoori1/laravel-microscope/code-structure\n[link-code-quality]: https://scrutinizer-ci.com/g/imanghafoori1/laravel-microscope\n[link-downloads]: https://packagist.org/packages/imanghafoori/laravel-microscope/stats\n[link-author]: https://github.com/imanghafoori1\n[link-contributors]: ../../contributors\n\n\n\u003ca name=\"contributors\"\u003e\u003c/a\u003e\n## ❤️ Contributors\n\nThis project exists thanks to all the people who contribute. [[Contributors](https://github.com/imanghafoori1/laravel-microscope/graphs/contributors)].\n\u003ca href=\"https://github.com/imanghafoori1/laravel-microscope/graphs/contributors\"\u003e\u003cimg src=\"https://opencollective.com/laravel-microscope/contributors.svg?width=890\u0026button=false\" /\u003e\u003c/a\u003e\n\n## ⭐ Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=imanghafoori1/laravel-microscope\u0026type=Date)](https://star-history.com/#imanghafoori1/laravel-microscope\u0026Date)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimanghafoori1%2Flaravel-microscope","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimanghafoori1%2Flaravel-microscope","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimanghafoori1%2Flaravel-microscope/lists"}