🤖

Laravel9でSeederにNamespaceを付けないで動くか検証してみた

2022/02/16に公開約3,300字

Laravelを9.xにバージョンアップする過程で8.xの変更点を見ていたら、
その中にSeederにNamespaceを付ける[1]変更点がありました。

ただ、Seederたくさんあるから付けないで動くなら付けたくない!って思ったので、付けないで動くか検証してみました。

環境

  • PHP v8.1.2
  • Laravel v9.1.0

環境はLaravel Sail[2]で作っています。

検証

Laravel7.xあたりで作成したSeederを持ってきて、Laravel9.x環境で実行してみます。

database/seeds/UserSeeder.php
database/seeds/UserSeeder.php
<?php

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class UserSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('users')->insert([
            'name' => Str::random(10),
            'email' => Str::random(10).'@gmail.com',
            'password' => Hash::make('password'),
        ]);
    }
}

持ってきたら、Artisanコマンドを使って実行します。

$ ./vendor/bin/sail artisan db:seed --class=UserSeeder

   Illuminate\Contracts\Container\BindingResolutionException 

  Target class [Database\Seeders\UserSeeder] does not exist.

  at vendor/laravel/framework/src/Illuminate/Container/Container.php:879
    875876▕         try {
    877$reflector = new ReflectionClass($concrete);
    878} catch (ReflectionException $e) {879▕             throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e);
    880}
    881882▕         // If the type is not instantiable, the developer is attempting to resolve
    883▕         // an abstract type such as an Interface or Abstract Class and there is

      +23 vendor frames 
  24  artisan:37
      Illuminate\Foundation\Console\Kernel::handle()

はい、失敗しましたー

なぜ、失敗したのか

実行したArtisanコマンドのコードを見てみると...

https://github.com/laravel/framework/blob/9.x/src/Illuminate/Database/Console/Seeds/SeedCommand.php#L92-L108
if (! str_contains($class, '\\')) {
    $class = 'Database\\Seeders\\'.$class;
}

強制的にNamespaceを付けていますね〜

結論

付けないとダメです!!

ディレクトリもdatabase/seeds -> database/seedersにリネームしなさいと書いてある時点で察していましたが、ダメでしたね...

大人しくバージョンアップの際に付けた方が良さそうです。

ちなみに...

Laravel8.x以前から別のNamespaceを付いている場合は、実行可能でした。

検証のために先ほどのコードにNamespaceを追加して実行してみます。

database/seeds/UserSeeder.php
database/seeds/UserSeeder.php
<?php

namespace Database\Seeds;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class UserSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('users')->insert([
            'name' => Str::random(10),
            'email' => Str::random(10).'@gmail.com',
            'password' => Hash::make('password'),
        ]);
    }
}

尚、実行する際はNamespace付きでクラスを指定する必要があります。

$ ./vendor/bin/sail artisan db:seed --class=Database\\Seeds\\UserSeeder
Database seeding completed successfully.

成功ですねー

結論2

強制的にNamespaceを付けている処理をみるとわかりますが、\\の有無で判定しているので、
Laravel8.xに上げる前からSeederをNamespace付きで作成しているなら、今回の変更点の影響はないように感じはします。

ただ、Laravelが用意したNamespaceと異なる状態になるので、何かしら動作に影響が出る可能性もあるので、合わせるほうが無難かもしれないです。
(どれくらいの修正が発生するかは規模次第ですね...)

脚注
  1. https://laravel.com/docs/8.x/upgrade#seeder-factory-namespaces ↩︎

  2. https://laravel.com/docs/9.x/sail ↩︎

Discussion

ログインするとコメントできます