-
Notifications
You must be signed in to change notification settings - Fork 325
Description
Fortify Version
1.30.0
Laravel Version
12.31.1
PHP Version
8.2.9
Database Driver & Version
No response
Description
When installing Laravel Fortify, the vendor/laravel/fortify/workbench/database/factories/UserFactory.php file creates a naming conflict with the application's own database/factories/UserFactory.php. This leads to IDE static analysis tools (e.g., PHP Intelephense in VS Code) indexing both files, resulting in incorrect type inference for factory methods like create(). Specifically:
- Intelephense generates a recursive/malformed type definition:
class UserFactory extends UserFactorywith@template TModel of \App\Models\Userand@extends \Illuminate\Database\Eloquent\Factories\Factory<TModel>. - This causes
$user = UserFactory::new()->create();to be inferred as\Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model>|\Illuminate\Database\Eloquent\Modelinstead of the expected\App\Models\User|\Illuminate\Database\Eloquent\Collection<int, \App\Models\User>, breaking autocomplete and diagnostics.
The conflict occurs because both factories are in the Database\Factories namespace and share the same class name. Fortify's workbench file extends \Orchestra\Testbench\Factories\UserFactory (for package testing), but it's unexpectedly included in the vendor index for end-user projects.
Steps To Reproduce
-
Create a fresh Laravel project:
composer create-project laravel/laravel example-app cd example-app -
Install Laravel Fortify to include the workbench directory:
composer require laravel/fortify
Verify that
vendor/laravel/fortify/workbench/database/factories/UserFactory.phpexists, containing:<?php namespace Database\Factories; use App\Models\User; /** * @template TModel of \App\Models\User * @extends \Illuminate\Database\Eloquent\Factories\Factory<TModel> */ class UserFactory extends \Orchestra\Testbench\Factories\UserFactory { protected $model = User::class; }
-
Generate the default application
UserFactory:php artisan make:factory UserFactory
Ensure
database/factories/UserFactory.phphas the standard structure:<?php namespace Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; /** * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User> */ class UserFactory extends Factory { public function definition(): array { return [ 'name' => fake()->name(), 'email' => fake()->unique()->safeEmail(), 'email_verified_at' => now(), 'password' => \Illuminate\Support\Facades\Hash::make('password'), 'remember_token' => \Illuminate\Support\Str::random(10), ]; } }
-
Create a test file (e.g.,
tests/Feature/UserFactoryTest.php) with:<?php namespace Tests\Feature; use Database\Factories\UserFactory; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; class UserFactoryTest extends TestCase { use RefreshDatabase; public function test_user_factory_creates_user(): void { $user = UserFactory::new()->create(); $this->assertNotNull($user); } }
-
Open the project in VS Code with the PHP Intelephense extension installed.
-
Hover over
UserFactoryin the test file (line$user = UserFactory::new()->create();) or use "Go to Definition" to view the generated type information. Intelephense shows conflicting definitions:Database\Factories\UserFactory <?php class UserFactory extends Factory { } @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User> Database\Factories\UserFactory <?php class UserFactory extends UserFactory { } @template TModel of \App\Models\User @extends \Illuminate\Database\Eloquent\Factories\Factory<TModel> -
Hover over
$userin the test file. Intelephense infers the type as:\Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model>|\Illuminate\Database\Eloquent\ModelInstead of the expected:
\Illuminate\Database\Eloquent\Collection<int, \App\Models\User>|\App\Models\User
The issue occurs due to the namespace collision between the application’s UserFactory and Fortify’s workbench UserFactory, causing Intelephense to misparse the class and fall back to generic type inference.