Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save chinleung/6ede73c5f5983c5b85c9fdcc5f0267e7 to your computer and use it in GitHub Desktop.

Select an option

Save chinleung/6ede73c5f5983c5b85c9fdcc5f0267e7 to your computer and use it in GitHub Desktop.
A command to perform basic migration from Laravel 7.x factories to Laravel 8.x

Description

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) with Model::factory() in factory class
  • Replace legacy factory(Model::class) with Model::factory() in tests

Instructions

  1. Rename database/factories into database/legacy-factories
  2. Create a command using php artisan make:command MigrateFactories
  3. Overwrite the command with the code content
  4. Run php artisan migrate:factories

Code

<?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;
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment