【Laravel+Breeze+Inertia+React】のpropsのauthはどこからでてくるのか
基本的なことなのかもしれませんが、初心者の私にとって忘れないようにするために記事にします。
環境はLaravel:9.44.0, php:8.0.9です。
ホーム画面のpropsについて
LalavelとBreeze、Inertia、Reactをインストールするとホーム画面は以下のような画面だと思います。インストール方法はこちらやこちらを参考にしました。
こちらの画面でchromeの拡張機能であるReact DevToolsを使ってデベロッパーツールからComponents選択すると受け取るpropsが以下のように確認できます。
ここで「/routes/web.php」を見てみると
<?php
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\InHouseFileController;
use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
/*
省略
*/
Route::get('/', function () {
return Inertia::render('Welcome', [
'canLogin' => Route::has('login'),
'canRegister' => Route::has('register'),
'laravelVersion' => Application::VERSION,
'phpVersion' => PHP_VERSION,
]);
});
/*
省略
*/
ホームにgetでアクセスした際には、Inertia::render
が返され、WelcomeというコンポーネントにcanLogin, canRegister, laravelVersion, phpVersionを渡してそうだなというのがわかります。しかし、authやerrors、ziggyについては記載がありません。
ではこれらはどこから出てきたのでしょうか。初心者の私は頭を抱えていました。
Inertia::renderを探す
Inertia::render
というファサード(Facade)は上記からuse Inertia\Inertia;
からきていることがわかります。これはどこかというと、「/vendor/inertiajs/inertia-laravel/src/Inertia.php」にありました。
<?php
namespace Inertia;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Facades\Facade;
/**
* @method static void setRootView(string $name)
* @method static void share($key, $value = null)
* @method static array getShared(string $key = null, $default = null)
* @method static array flushShared()
* @method static void version($version)
* @method static int|string getVersion()
* @method static LazyProp lazy(callable $callback)
* @method static Response render($component, array|Arrayable $props = [])
* @method static \Symfony\Component\HttpFoundation\Response location(string $url)
*
* @see \Inertia\ResponseFactory
*/
class Inertia extends Facade
{
protected static function getFacadeAccessor(): string
{
return ResponseFactory::class;
}
}
ここからInertia::render
がResponseFactory::class
にあることがわかります。
そこでResponseFactory::class
を見てみると、
<?php
namespace Inertia;
use Closure;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Response as BaseResponse;
use Illuminate\Support\Traits\Macroable;
class ResponseFactory
{
use Macroable;
/** @var string */
protected $rootView = 'app';
/** @var array */
protected $sharedProps = [];
/** @var Closure|string|null */
protected $version;
public function setRootView(string $name): void
{
$this->rootView = $name;
}
/**
* @param string|array|Arrayable $key
* @param mixed|null $value
*/
public function share($key, $value = null): void
{
if (is_array($key)) {
$this->sharedProps = array_merge($this->sharedProps, $key);
} elseif ($key instanceof Arrayable) {
$this->sharedProps = array_merge($this->sharedProps, $key->toArray());
} else {
Arr::set($this->sharedProps, $key, $value);
}
}
/*
省略
*/
/**
* @param string $component
* @param array|Arrayable $props
* @return Response
*/
public function render(string $component, $props = []): Response
{
if ($props instanceof Arrayable) {
$props = $props->toArray();
}
return new Response(
$component,
array_merge($this->sharedProps, $props),
$this->rootView,
$this->getVersion()
);
}
/*
省略
*/
render関数がありました。「/routes/web.php」ではこれを呼んでいたわけですね。第1引数がWelcome、第2引数がpropsに渡っていた変数です。returnでResponseインスタンスを返して画面を表示しているんですね。
authはどこから
ただrender関数を見てもauth等の記述はありません。怪しいのは、array_merge($this->sharedProps, $props)
の部分で、$props
は引数でしたので、$this->sharedProps
の方ですね。$this->sharedProps
はResponseFactory::class
のshare関数で値が取得されているみたいです。
ではこのshare関数はどこで実行されているのでしょうか。
今度はMiddlewareの方を確認してみます。Middlewareは「/app/Http/Kernel.php」にまとめられています。
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/*
省略
*/
/**
* The application's route middleware groups.
*
* @var array<string, array<int, class-string|string>>
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\HandleInertiaRequests::class, // ←これ
\Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets::class,
//\App\Http\Middleware\SetLocale::class,
],
'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
/*
省略
*/
$middlewareGroups
に\App\Http\Middleware\HandleInertiaRequests::class,
があります。これを見てみましょう。
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Inertia\Middleware;
use Tightenco\Ziggy\Ziggy;
class HandleInertiaRequests extends Middleware
{
/**
* The root template that is loaded on the first page visit.
*
* @var string
*/
protected $rootView = 'app';
/**
* Determine the current asset version.
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
public function version(Request $request)
{
return parent::version($request);
}
/**
* Define the props that are shared by default.
*
* @param \Illuminate\Http\Request $request
* @return mixed[]
*/
public function share(Request $request)
{
return array_merge(parent::share($request), [
'auth' => [
'user' => $request->user(),
],
'ziggy' => function () use ($request) {
return array_merge((new Ziggy)->toArray(), [
'location' => $request->url(),
]);
},
]);
}
}
なんかそれっぽいshare関数がありました。ばっちりauthとziggyの記載があります。そこでこのshare関数を実行している部分を探します。
Middlewareは実行するされる際にhandle関数を実行するという決まりがあります。そこでこのHandleInertiaRequests::class
がclass HandleInertiaRequests extends Middleware
で継承しているMiddleware
を見てみます。これはuse Inertia\Middleware;
からわかる通り「/vendor/inertiajs/inertia-laravel/src/Middleware.php」にあります。
<?php
namespace Inertia;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Symfony\Component\HttpFoundation\Response;
class Middleware
{
/*
省略
*/
/**
* Defines the props that are shared by default.
*
* @see https://inertiajs.com/shared-data
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function share(Request $request)
{
return [
'errors' => function () use ($request) {
return $this->resolveValidationErrors($request);
},
];
}
/*
省略
*/
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param Closure $next
* @return Response
*/
public function handle(Request $request, Closure $next)
{
Inertia::version(function () use ($request) {
return $this->version($request);
});
Inertia::share($this->share($request)); // ←これ
Inertia::setRootView($this->rootView($request));
$response = $next($request);
$response->headers->set('Vary', 'X-Inertia');
if (! $request->header('X-Inertia')) {
return $response;
}
if ($request->method() === 'GET' && $request->header('X-Inertia-Version', '') !== Inertia::getVersion()) {
$response = $this->onVersionChange($request, $response);
}
if ($response->isOk() && empty($response->getContent())) {
$response = $this->onEmptyResponse($request, $response);
}
if ($response->getStatusCode() === 302 && in_array($request->method(), ['PUT', 'PATCH', 'DELETE'])) {
$response->setStatusCode(303);
}
return $response;
}
/*
省略
*/
handle関数がありましたね。そのなかにInertia::share($this->share($request));
があると思います。このInertia::share
の部分が最初の方に確認したResponseFactory::class
のshare関数で、Welcomeコンポーネントに渡す$sharedProps
を取得しています。
引数である$this->share($request)
はHandleInertiaRequests
のshare関数でここでauthとziggyが取得されています。
ついでにこのHandleInertiaRequests
のshare関数の1行目の
return array_merge(parent::share($request), [
のparent::share($request)
が継承元のMiddleware::class
のshare関数でerrorsを取得していることがわかります。
これでようやく全部取得しているルートがわかりました。めでたしめでたし。
まとめ
これまでの流れをまとめるとホーム画面にauth等が渡る流れとしては、
- Middlewareでauth情報の取得
- /vendor/inertiajs/inertia-laravel/src/Middleware.php -> handle()
- /app/Http/Middleware/HandleInertiaRequests.php -> share() #auth,ziggy
- /vendor/inertiajs/inertia-laravel/src/Middleware.php -> share() #errors
- Inertia::render()でレンダリング
- /vendor/inertiajs/inertia-laravel/src/ResponseFactory.php -> render()
本来は突き詰めるなら$request->user()
の部分の取得までやるべきかもしれませんが、元気がありません。なかなか初心者には難しいですね。でかziggyってなに。
Discussion