PHPackages                             imanghafoori/laravel-self-test - 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. imanghafoori/laravel-self-test

Abandoned → [imanghafoori/laravel-microscope](/?search=imanghafoori%2Flaravel-microscope)Library[Testing &amp; Quality](/categories/testing)

imanghafoori/laravel-self-test
==============================

Automatically test your laravel application

v1.0.436(2mo ago)1.5k12396[3 issues](https://github.com/imanghafoori1/laravel-microscope/issues)MITPHPPHP ^7.4|8.0.\*|8.1.\*|8.2.\*|8.3.\*|8.4.\*|8.5.\*CI passing

Since Mar 23Pushed 2w ago21 watchersCompare

[ Source](https://github.com/imanghafoori1/laravel-microscope)[ Packagist](https://packagist.org/packages/imanghafoori/laravel-self-test)[ Docs](https://github.com/imanghafoori1/laravel-microscope)[ RSS](/packages/imanghafoori-laravel-self-test/feed)WikiDiscussions master Synced yesterday

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

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

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

 [![microscope_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/3303011f5c2c37c6f65bd27c321b219d10ce15229011da4ad67de4d8d06f4140/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d254532253839254135253230352e362d6666326432303f7374796c653d666c61742d737175617265266c6f676f3d6c61726176656c)](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)[![Coverage Status](https://camo.githubusercontent.com/b261b892fbbe5eb56510c9861aca5f142782568fa5fad958c3bcab873f30a293/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f696d616e676861666f6f7269312f6c61726176656c2d6d6963726f73636f70652f62616467652e7376673f6272616e63683d6d6173746572)](https://coveralls.io/github/imanghafoori1/laravel-microscope?branch=master)

- 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)
    - [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:imports`](#imports)
        5. [`php artisan check:bad_practices`](#bad_practices)
        6. [`php artisan check:routes`](#routes)
        7. [`php artisan check:compact`](#compact)
        8. [`php artisan check:blade_queries`](#blade_queries)
        9. [`php artisan check:extract_blades`](#extract_blades)
        10. [`php artisan check:action_comments`](#action_comments)
        11. [`php artisan check:views`](#views)
        12. [`php artisan check:gates`](#gates)
        13. [`php artisan check:aliases`](#aliases)
        14. [`php artisan check:dead_controllers`](#dead_controllers)
        15. [`php artisan check:generic_docblocks`](#generic_docblocks)
        16. [`php artisan check:migrations`](#migrations)
        17. [`php artisan check:empty_comment`](#empty_comment)
        18. [`php artisan enforce:helper_functions`](#helper_functions)
        19. [`php artisan check:extra_fqcn`](#fqcn)
        20. [`php artisan list:models`](#models)
        21. [`php artisan check:extra_imports`](#extra_imports)
        22. [`php artisan enforce:imports`](#enforce_imports)
        23. [`php artisan check:abort_if`](#check_abort_if)

    - [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 Used Commands:

[](#less-used-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 check:abort_if`13`php artisan list:models`14`php artisan check:endif`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 enforce:imports`23`php artisan check:fqcn`

📖 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} {--except-folder=} {--except-file=}`

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

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 parentheses.
- 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-insensitive)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 classpath 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" that contain the word "todo:" in them.

```
 'todo_comments' => [
        'search' => '',
        'predicate' => function($matches) {    //   ',
      '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 by `query`

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

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

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

Let's say we want to opt into PHP v7.4 arrow functions:

```
'fn' => [
    'search' => 'function (){ return ; }',
    'replace' => 'fn () => ',
    'tags' => 'php74,refactor',
]
```

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 in which you can not use `;` to cover it properly!

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

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

    return $a;
};
```

If we define our pattern like this:

```
return [
    'pattern_name' => [
        '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 the closure definition and the 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 would the pattern 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:

```
