I am having a hard to figuring out how to refractor a factory in Laravel 7 to Laravel 8. Below is the original factory in L7 and the L8 version below is the one I've tried refactoring. I know the $factory->define
is wrong and this is where I am stuck.
Laravel 7 Version
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\Login;
use Faker\Generator as Faker;
$factory->define(Login::class, function (Faker $faker) {
$randomDateTime = $faker->dateTimeBetween('-6 hours', 'now');
return [
'user_id' => factory(App\User::class),
'tenant_id' => factory(App\Tenant::class),
'created_at' => $randomDateTime,
'updated_at' => $randomDateTime,
];
});
Laravel 8 Version
<?php
namespace Database\Factories;
use App\Models\Login;
use App\Models\Tenant;
use App\Models\User;
use Faker\Generator as Faker;
$factory->define(Login::class, function (Faker $faker) {
$randomDateTime = $faker->dateTimeBetween('-6 hours', 'now');
return [
'user_id' => User::factory(),
'tenant_id' => Tenant::factory(),
'created_at' => $randomDateTime,
'updated_at' => $randomDateTime,
];
});
CodePudding user response:
You have two options here:
Use old factories
If you don't have the time for properly refactoring your factories, you can still use your old Laravel 7 factories by pulling in the laravel/legacy-factories
package:
composer require laravel/legacy-factories
Refactor your factories
Laravel 8 factories are now classes. Previously, you would call a define method on the $factory
object, passing it the class and a closure that would return the factory definition like so:
<?php
use App\User;
use Faker\Generator as Faker;
use Illuminate\Support\Str;
$factory->define(User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi',
'remember_token' => Str::random(10),
];
});
In Laravel 8, the same would be written as follows and be put in database/factories/UserFactory.php
for auto-discovery:
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi',
'remember_token' => Str::random(10),
];
}
}
As you see, factories are now separate classes that extend from the Illuminate\Database\Eloquent\Factories\Factory
class.
Additionally, you need to use the Illuminate\Database\Eloquent\Factories\HasFactory
trait on the Model to allow the discovery of factories for the Model. Once you add this trait, Laravel expects a Factory class by the name of the Model, suffixed with Factory
in the database/factories
folder.
You can read up on all that in the Defining Model Factories chapter of the database testing documentation.
In your specific case
The code you posted would need to be refactored and put in database/factories/LoginFactory.php
:
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class LoginFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
$randomDateTime = $faker->dateTimeBetween('-6 hours', 'now');
return [
'user_id' => User::factory(),
'tenant_id' => Tenant::factory(),
'created_at' => $randomDateTime,
'updated_at' => $randomDateTime,
];
}
}
Then you need to use Illuminate\Database\Eloquent\Factories\HasFactory;
in your Login.php
model class and of course you would have do the same for the User
and Tenant
models, creating UserFactory.php
and TenantFactory.php
.