PHPackages                             holdon1996/laravel\_microscope\_custom - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. holdon1996/laravel\_microscope\_custom

ActiveLibrary[Testing &amp; Quality](/categories/testing)

holdon1996/laravel\_microscope\_custom
======================================

Automatically test your laravel application

v2.0(2y ago)014MITPHPPHP ^7.1.3|8.0.\*|8.1.\*|8.2.\*

Since Jul 21Pushed 2y ago1 watchersCompare

[ Source](https://github.com/holdon1996/laravel-microscope_custom)[ Packagist](https://packagist.org/packages/holdon1996/laravel_microscope_custom)[ Docs](https://github.com/holdon1996/laravel-microscope_custom)[ RSS](/packages/holdon1996-laravel-microscope-custom/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (9)Dependencies (9)Versions (10)Used By (0)

 Find Bugs Before They Bite
----------------------------

[](#-----find-bugs-before-they-bite)

 [![widgetize_header](https://user-images.githubusercontent.com/6961695/78522127-920e9e80-77e1-11ea-869a-05a29466e6b0.png)](https://user-images.githubusercontent.com/6961695/78522127-920e9e80-77e1-11ea-869a-05a29466e6b0.png)

#### Built with ❤️ for lazy laravel developers ;)

[](#built-with-heart-for-lazy-laravel-developers-)

### Why repeat the old errors, if there are so many new errors to commit?

[](#why-repeat-the-old-errors-if-there-are-so-many-new-errors-to-commit)

### (Bertrand Russel)

[](#bertrand-russel)

##### Give your eyes a rest, we will detect and fix them for you.

[](#give-your-eyes-a-rest-we-will-detect-and-fix-them-for-you)

[![Packagist Stars](https://camo.githubusercontent.com/2c0582954d9bc62df30289d90eb66e1644a632bf00d58798c71c1eac01bd3e68/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f73746172732f696d616e676861666f6f72692f6c61726176656c2d6d6963726f73636f7065)](https://camo.githubusercontent.com/2c0582954d9bc62df30289d90eb66e1644a632bf00d58798c71c1eac01bd3e68/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f73746172732f696d616e676861666f6f72692f6c61726176656c2d6d6963726f73636f7065)[![Required Laravel Version](https://camo.githubusercontent.com/7d14a11c9186ca3eb1e5180278de09d1e0f9ee93d59d95fbf37b1e64190345d8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d254532253839254135253230352e342d6666326432303f7374796c653d666c61742d737175617265266c6f676f3d6c61726176656c)](https://packagist.org/packages/imanghafoori/laravel-microscope)[![Required PHP Version](https://camo.githubusercontent.com/b23b1798bb27320b9abf03c6794f8c1340e93a8c725dcd24c4f6a84fc4637b0c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f696d616e676861666f6f72692f6c61726176656c2d6d6963726f73636f70653f636f6c6f723d253233383839324246267374796c653d666c61742d737175617265266c6f676f3d706870)](https://packagist.org/packages/imanghafoori/laravel-microscope)[![Latest Version on Packagist](https://camo.githubusercontent.com/7cd0b8241dbd082e4fe601b494150203b1cb2c4124bf1de3e4bb98a268e65a6e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f696d616e676861666f6f72692f6c61726176656c2d6d6963726f73636f70652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/imanghafoori/laravel-microscope)[![Quality Score](https://camo.githubusercontent.com/f22276cda788392874720a364011a382826b50fd52621c852bf855911823eb97/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f672f696d616e676861666f6f7269312f6c61726176656c2d6d6963726f73636f70652e7376673f7374796c653d666c61742d737175617265266c6f676f3d7363727574696e697a6572)](https://scrutinizer-ci.com/g/imanghafoori1/laravel-microscope)[![Total Downloads](https://camo.githubusercontent.com/8d077172b82097f170a9c0ea08ca299e0f07ec77b65d6f8b91192a127734bc0f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f696d616e676861666f6f72692f6c61726176656c2d6d6963726f73636f70652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/imanghafoori/laravel-microscope/stats)[![Today Downloads](https://camo.githubusercontent.com/c7449999a83af66a9e9d79b0a6cc6d3ecb2642908b6ea46d96369034e49167c6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64642f696d616e676861666f6f72692f6c61726176656c2d6d6963726f73636f70652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/imanghafoori/laravel-microscope/stats)

- Table Of Contents

    - [Key Things To Know](#key-things-to-know)
    - [Installation](#installation)
    - [Usage](#usage)

        - [Useful Commands](#useful-commands)
        - [Fewer Use Commands](#less-use-commands)
        - [Gloabl Helper Functions](#global-helper-functions)
    - [What The Commands Do?](#what-the-commands-do)

         show commands
        1. [`php artisan search_replace`](#search_replace)

            - [Defining Patterns](#defining-patterns)
            - [Placeholders](#placeholders)
            - [Mutator](#mutator)
            - [Filters](#filters)
            - [Capturing Php "statements"](#capturing-php-statements)
            - [Capturing Global Function Calls](#capturing-global)
            - [Repeating Patterns](#repeating-patterns)
        2. [`php artisan check:early_returns`](#early_returns)
        3. [`php artisan check:psr4`](#psr4)
        4. [`php artisan check:generate`](#generate)
        5. [`php artisan check:imports`](#imports)
        6. [`php artisan check:bad_practices`](#bad_practices)
        7. [`php artisan check:routes`](#routes)
        8. [`php artisan check:compact`](#compact)
        9. [`php artisan check:blade_queries`](#blade_queries)
        10. [`php artisan check:extract_blades`](#extract_blades)
        11. [`php artisan check:action_comments`](#action_comments)
        12. [`php artisan pp:route`](#route)
        13. [`php artisan check:views`](#views)
        14. [`php artisan check:events`](#events)
        15. [`php artisan check:gates`](#gates)
        16. [`php artisan check:aliases`](#aliases)
        17. [`php artisan check:dead_controllers`](#dead_controllers)
        18. [`php artisan check:generic_docblocks`](#generic_docblocks)
        19. [`php artisan enforce:helper_functions`](#helper_functions)
        20. [`php artisan list:models`](#models)

    - [Credits](#credits)
    - [License](#license)
    - [Contributing](#contributing)
    - [More From The Author](#more-from-author)
    - [Contributors](#contributors)

Key things to know:
-------------------

[](#key-things-to-know)

- It is created to be **smarter than phpstorm** and other IDEs in finding errors.
- It is created to **understand laravel run-time** and magic.
- It does **not show you stupid false errors**, all the reported cases are really errors.
- Even If you have written a lot of tests for your app, **you may still need this**.
- **It can refactor your code**, by applying `early returns` automatically.
- It is written from scratch to yield the **maximum performance** possible.

### 🎞️ Video tutorial [here](https://youtu.be/aEkiE30wNKk)

[](#film_strip-video-tutorial-here)

### ⭐ Your Stars Make Us Do More

[](#star-your-stars-make-us-do-more)

> If 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.

[Stargazers](https://github.com/imanghafoori1/microscope/stargazers)

⬇️ Installation
---------------

[](#️-installation)

You can **install** the package via composer:

```
composer require imanghafoori/laravel-microscope --dev
```

You may also **publish** config file:

```
php artisan vendor:publish --provider="Imanghafoori\LaravelMicroscope\LaravelMicroscopeServiceProvider"

```

💎 Usage:
--------

[](#-usage)

### Useful Commands:

[](#useful-commands)

> You can run 👇

\#Artisan Command1`php artisan search_replace`2`php artisan check:early_returns`3`php artisan check:all`

### Less Use Commands

[](#less-use-commands)

\#Artisan Command1`php artisan check:views`2`php artisan check:routes`3`php artisan check:psr4 {-s|--nofix} `4`php artisan check:imports {-s|--nofix}`5`php artisan check:stringy_classes`6`php artisan check:dd`7`php artisan check:bad_practices`8`php artisan check:compact`9`php artisan check:blade_queries`10`php artisan check:action_comments`11`php artisan check:extract_blades`12`php artisan pp:route`13`php artisan check:generate`14`php artisan check:endif`15`php artisan check:events`16`php artisan check:gates`17`php artisan check:dynamic_where`18`php artisan check:aliases`19`php artisan check:dead_controllers`20`php artisan check:generic_docblocks`21`php artisan enforce:helper_functions`22`php artisan list:models`

Global Helper Functions
-----------------------

[](#global-helper-functions)

> Also, You will have access to some global helper functions

```
microscope_dd_listeners($event);
```

In case you wonder what the listeners are and where they are, you can call `microscope_dd_listeners(MyEvent::class);` within either the `boot` or `register` methods. It works like a normal `dd(...);` meaning that the program stops running at that point.

📖 What do the Commands do?
--------------------------

[](#-what-do-the-commands-do)

Let's start with the:

### `php artisan search_replace {--name=pattern_name} {--tag=some_tag} {--file=partial_file_name} {--folder=partial_folder_name}`

[](#php-artisan-search_replace---namepattern_name---tagsome_tag---filepartial_file_name---folderpartial_folder_name)

This is a smart and very powerful search/replace functionality that can be a real "time saver" for you.

#### 1️⃣ Defining patterns:

[](#onedefining-patterns)

> If you run the command `artisan search_replace` for the first time, it will create a `search_replace.php` file in the project's root. Then, you can define your patterns, within that file.

**Examples:**

Let's define a pattern to replace the `optional()` global helper with the `?->` php 8 null safe operator:

```
return [
    'optional_to_nullsafe' => [
        'search' => '""("")->',
        'replace' => '""?->',
        // 'tag' => 'php8,refactor',
        // 'predicate' => function($matches, $tokens) {...},
        // 'mutator' => function($matches) {...},
        // 'post_replace' => [...],
        // 'avoid_result_in' => [...],
        // 'avoid_syntax_errors' => false,
        // 'filters' => [...],
    ]
];
```

- 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`)
- The search pattern has a `""` placeholder which captures everything in between the pair of parenthesis.
- In the `replace` block we substitute what we have captured by the first placeholder with the `""`. If we have more placeholders, we could have had `""` etc.
- In the tag block we can mention some tags as an array of strings or a string separated by commas and target them by `--tag` flag: `php artisan search_replace --tag=php8`

2️⃣ **Placeholders:**

Here is a comprehensive list of placeholders you can use:

\#PlaceholdersDescription1`` or ``for variables like: `$user`2`` or ``for hard coded strings: `'hello'` or "hello"3``for class references: `\App\User::where(...` , `User::where`4``only for full references: `\App\User::`5``to capture all the code until you reach a certain character.6``for comments (it does not capture doc-blocks beginning with: /\*\* )7``for php doc-blocks8``to capture a whole php statement.9`` or ``for method or function names. `->where` or `::where`10``for whitespace blocks11`` or ``for true or false (acts case-insensetive)12``for numeric values13``for type-casts like: `(array) $a;`14`` or `""`for integer values15``for public, protected, private16``for floating point number17`""`to detect global function calls18``to capture code within a pair of `{...}` or `(...)` or `[...]`19``captures any token.> You can also define your own keywords if needed!
>
> You just define a class for your new keyword and append the class path to the end of the `Finder::$keywords[] = MyKeyword::class` property. Just like the default keywords.

**Example:**

1️⃣ Let's say you want to find only the "comments" which contain the word "todo:" in them.

```
 'todo_comments' => [
        'search' => '',
        'predicate' => function($matches) {    //    [
        'search' => '?]',
        'replace' => ',""]',
        'avoid_syntax_errors' => true,
        'avoid_result_in' => [
           ',,]',
           '[,]',
           '[,]'
       ],
    ]
```

In this case, our pattern is not very accurate and in some cases, it may result in syntax errors. Because of that, we turn on php syntax validator to check the result, but that costs us a performance penalty!!! To 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.

- **Note**: The `?` in the "&lt;white\_space&gt;?" notes this is an `optional` placeholder.

If you are curious to see a better pattern which does not need any syntax checking, try this:

```
'enforce_optional_comma' => [
       'search' => '?[]',
       'replace' => '[,]',
       'avoid_result_in' => [
           ',,]',
           '[,]'
       ],
       'predicate' => function ($matches) {
           $type = $matches['values'][0][0];

           return $type !== T_VARIABLE && $type !== ']';
       },
       'post_replace' => [
           ',]' => ',]'
       ]
],

```

This is more complex but works much faster. (since it does not need the php syntax validator)

- Here `'post_replace'` is a pattern which is applied only and only on the resulting code to refine it, and NOT on the entire file.
- You can optionally comment your placeholders (as above ``) with numbers, so that you know which one corresponds to which when replaced.

4️⃣ **Filters:**

Currently, the microscope offers only two built-in filters: `is_sub_class_of` and `in_array`

Can you guess what the heck this pattern is doing?!

```
 'mention_query' => [
      'search' => '::'
      'replace' => '::query()->',
      'filters' => [
          1 => [
              'is_sub_class_of' => \Illuminate\Database\Eloquent\Model::class
          ],
          2 => [
              'in_array' => 'where,count,find,findOrFail,findOrNew'
          ]
      ]
  ]
```

It converts these:

```
User::where(...)->get();

\App\Models\User::find(...);
```

Into these:

```
User::query()->where(...)->get();

\App\Models\User::query()->find(...);
```

- 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.

So it does not tamper with something like this:

```
User::all();            // The `all` method can not be preceded with `query`

UserRepo::where(...);   /// UserRepo is not a model
```

- This is something which you can never do by regex.

5️⃣ **Capturing php "statements":**

Let's say we want to opt into php 7.4 arrow functions:

```
'fn' => [
    'search' => 'function (){  }',
    'replace' => 'fn () => ',
    'tags' => 'php74,refactor',
    'mutator' => function ($matches) {
      $matches[2][1] = str_replace(['return ', ';'], '', $matches[2][1]);

      return $matches;
    }
]
```

In this example, we have mentioned one single "statement" in the body of the function. So if it encounters a function with two or more statements it will ignore that.

```
$closure = function ($a) use ($b) {
    return $a + $b;
};

// will become:
$closure = fn($a) => $a + $hello;
```

But this is not captured:

```
$closure = function ($a) {
    $a++;
    return $a + $b;
};
```

6️⃣ **Difference between `` and `;`**

They seem to be very similar but there is an important case which you can not use `;` in order to cover it properly!

```
$first = $a + $b;

$second = function ($a) {
    $a++;

    return $a;
};
```

If we define our pattern like this:

```
return [
    'staty' => [
        'search' => ' = ;',
    ]
];
```

For `$c = $a + $b;` they act the same way, but for the second one `"";` will not capture the whole closure and will stop as soon as it reaches `$a++;` and that is a problem.

But if you define your pattern as: `' = '` it would be smart enough to capture the correct semicolon at the end of closure definition and whole close would be captured.

7️⃣ **Capturing global function calls:**

Let's say you want to eliminate all the `dd(...)` or `dump(...)` before pushing to production.

```
return [
    'remove_dd' => [
        'search' =>  "''('');",
        'replace' => ''
    ]
];
```

This will NOT capture cases like below:

```
$this->  dd('hello');          // is technically a method call
User::   dd('I am static');    // is technically a static method call
new      dd('I am a class');  // here "dd" is the name of a class.

```

But will detect and remove real global `dd()` calls with whatever parameters they have received.

```
dd(                // user()->id
);

\dd(1);
dd(1);
dump(1);

```

8️⃣ **Repeating patterns:**

Let's say we want to refactor:

```
User:where('name', 'John')->where('family', 'Dou')->where('age', 20)->get();
```

into:

```
User:where([
    'name' => 'John',
    'family' => 'Dou',
    'age'=> 20,
])->get();
```

Ok, how the pattern would look like then?!

```
"group_wheres" => [

       'search' => '::where('', '')''->get();'

       'replace' => '::where([
            => ,
           ""])->get();',

       'named_patterns' => [
           'wheres' => '->where(, )?',
           'key_values' => ' => ,',
       ]
   ]
```

Nice yeah??!

> Possibilities are endless and the sky is the limit...

### `php artisan check:early_returns`

[](#php-artisan-checkearly_returns)

This will scan all your Psr-4 loaded classes and flattens your functions and loops by applying the early return rule. For example:

```
