Laravel コントローラをtinkerから実行する

tinkerからコントローラを実行できると便利なので、その方法をご紹介します。

## 環境

- PHP: 8.0.10
- Laravel: 8.58.0

## 関連記事

- [Laravel 標準搭載のデバッグ機能 tinker コマンドのご紹介](https://qiita.com/ucan-lab/items/0e9537be6d5709e1d099)

## モデル、コントローラを作る

```shell
$ php artisan make:model Book
$ php artisan make:controller BookController
```

- `app/Models/Book.php`
- `app/Http/Controllers/BookController.php`

### index: 引数なしのメソッドを実行する

```php:app/Http/Controllers/BookController.php
<?php declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\Book;
use Illuminate\Http\Request;

final class BookController extends Controller
{
    /**
     * @return array
     */
    public function index(): array
    {
        return [
            'data' => [
                'id' => 1,
                'name' => 'PHP Book',
            ]
        ];
    }
}
```

だいぶ適当な関数ですが、これをtinkerから実行してみます。

```shell
$ php artisan tinker

>>> $controller = app()->make(\App\Http\Controllers\BookController::class);
=> App\Http\Controllers\BookController {#3449}

>>> app()->call([$controller, 'index']);
=> [
     "data" => [
       "id" => 1,
       "name" => "PHP Book",
     ],
   ]
```

コントローラをtinkerから実行できました！

### store: Requestオブジェクトのあるメソッドを実行する

```php:app/Http/Controllers/BookController.php
<?php declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\Book;
use Illuminate\Http\Request;

final class BookController extends Controller
{
    /**
     * @param Request $request
     * @return array
     */
    public function store(Request $request): array
    {
        return [
            'data' => $request->all(),
        ];
    }
}
```

`Request` オブジェクトが必要な時の例です。

```shell
$ php artisan tinker

>>> $params = ['name' => 'Laravel Book'];
=> [
     "name" => "Laravel Book",
   ]

>>> $request = \Illuminate\Http\Request::create('/books', 'POST', $params);
=> Illuminate\Http\Request {#3452
     +attributes: Symfony\Component\HttpFoundation\ParameterBag {#3448},
     +request: Symfony\Component\HttpFoundation\InputBag {#3450},
     +query: Symfony\Component\HttpFoundation\InputBag {#3449},
     +server: Symfony\Component\HttpFoundation\ServerBag {#3441},
     +files: Symfony\Component\HttpFoundation\FileBag {#3440},
     +cookies: Symfony\Component\HttpFoundation\InputBag {#3446},
     +headers: Symfony\Component\HttpFoundation\HeaderBag {#3444},
   }

>>> $controller = app()->make(\App\Http\Controllers\BookController::class);
=> App\Http\Controllers\BookController {#3442}

>>> app()->call([$controller, 'store'], ['request' => $request]);
=> [
     "data" => [
       "name" => "Laravel Book",
     ],
   ]
```

### show: Bookオブジェクトのあるメソッドを実行する

```php:app/Http/Controllers/BookController.php
<?php declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\Book;
use Illuminate\Http\Request;

final class BookController extends Controller
{
   /**
     * @param Book $book
     * @return array
     */
    public function show(Book $book): array
    {
        return [
            'data' => [
                'id' => $book->id,
                'name' => $book->name,
            ],
        ];
    }
}
```

`Book` モデルのオブジェクトが必要な時の例です。

```shell
$ php artisan tinker

>>> $book = \App\Models\Book::factory()->make(['id' => 1, 'name' => 'PHP Book', 'created_at' => now(), 'updated_at' => now()]);

=> App\Models\Book {#4379
     id: 1,
     name: "PHP Book",
     created_at: "2021-09-01 00:00:00",
     updated_at: "2021-09-01 00:00:00",
   }

>>> $controller = app()->make(\App\Http\Controllers\BookController::class);
=> App\Http\Controllers\BookController {#4384}

>>> app()->call([$controller, 'show'], ['book' => $book]);
=> [
     "data" => [
       "id" => 1,
       "name" => "PHP Book",
     ],
   ]
```

今回はDB作ってないので、`Book::factory()` でBookインスタンスだけ作ってます。
DBがある場合は `$book = \App\Models\Book::find(1);` 等でBookインスタンス取得してください。

## 参考

- https://mellowhost.com/blog/how-to-call-a-controller-method-from-tinker-laravel.html
- https://gist.github.com/nasirkhan/809eee36875dc7c1935bc4289be214c6