A simple command to create factory classes for Laravel 8.x based on your Laravel 7.x factories definitions.
This command performs the following changes:
- Create missing factory classes
- Fill up definition function of the factory class
- Import existing namespaces into factory class
- Replace legacy
factory(Model::class)withModel::factory()in factory class - Replace legacy
factory(Model::class)withModel::factory()in tests
- Rename
database/factoriesintodatabase/legacy-factories - Create a command using
php artisan make:command MigrateFactories - Overwrite the command with the code content
- Run
php artisan migrate:factories
<?php
namespace App\Console\Commands;
use Exception;
use Illuminate\Console\Command;
class MigrateFactories extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'factories:migrate';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Migrate the legacy factories to classes';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
collect(glob(base_path('database/legacy-factories/*.php')))
->reject(static fn ($path) => file_exists(str_replace('legacy-factories', 'factories', $path)))
->each(function ($legacy) {
$file = basename($legacy);
$path = base_path("database/factories/{$file}");
$this->call('make:factory', [
'name' => basename($path, '.php'),
]);
$legacyContent = file_get_contents($legacy);
if (! preg_match('/function\s\(Faker \$faker\)\s{\s+(.*)}\);$/s', $legacyContent, $match)) {
throw new Exception('Unable to retrieve content from legacy factory.');
}
$content = preg_replace('/(\n\s)/', '$1 ', end($match));
$content = preg_replace('/factory\((.*)::class\)/', '$1::factory()', $content);
$factory = file_get_contents($path);
$factory = preg_replace('/return\s\[\n\s+\/\/\n\s+];/', rtrim($content, "\n"), $factory);
$factory = str_replace('$faker', '$this->faker', $factory);
preg_match_all('/use\s[^;]+;/', $legacyContent, $matches);
foreach ($matches[0] as $namespace) {
if ($namespace == 'use Faker\Generator as Faker;') {
continue;
}
if (strpos($factory, $namespace) !== false) {
continue;
}
$factory = preg_replace('/(namespace\sDatabase\\\Factories;\n\n)/', "$1{$namespace}\n", $factory);
}
file_put_contents($path, $factory);
});
collect(glob(base_path('tests/**/*.php')))
->each(static function ($test) {
$content = file_get_contents($test);
while (preg_match('/factory\([^:]+::class\)/', $content)) {
$content = preg_replace('/factory\(([^:]+::)class\)/', '$1factory()', $content);
}
file_put_contents($test, $content);
});
return 0;
}
}