Skip to content

Instantly share code, notes, and snippets.

@jasonvarga
Last active April 29, 2019 10:27
Show Gist options
  • Save jasonvarga/dda8e8a4a88ab696ad983346cc9f553b to your computer and use it in GitHub Desktop.
Save jasonvarga/dda8e8a4a88ab696ad983346cc9f553b to your computer and use it in GitHub Desktop.

Class-based Model Factory Tweaks

I loved John's post about class-based model factories and wanted to take it a couple of steps further.

Problem: Multiple facade-based uses behave statically

From https://twitter.com/jason_varga/status/998352169412775936
Caleb's solution: https://twitter.com/calebporzio/status/998569618103992320

My adapted solution:

  • Make an abstract factory class that handles clearing the resolved instance
  • Change the create method in the child factory classes to model

Tweak: Prevent extra use statements

I wasn't super fond of importing a separate class with a Factory suffix. My IDE's import command kept importing the actual factory class instead of the facade.

Instead of needing to use Facades\MyFactory throughout tests, we can add a factory() method to the model's class. Also, since the docblock returns the actual factory class, your IDE gives the appropriate method hints.

In tests, you're probably already importing the model anyway so now there's one less thing to worry about.

Before:

use App\Season;
use Facades\App\Factories\SeasonFactory;

SeasonFactory::create();
Season::count(); // Maybe you're making assertions using the model class 

After:

use App\Season;

Season::factory()->create();
Season::count();
<?php
namespace App\Factories;
abstract class Factory
{
public function instance()
{
return $this;
}
public function create()
{
$facade = '\\Facades\\' . static::class;
$facade::clearResolvedInstance(static::class);
return $this->model();
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Season extends Model
{
//
/**
* @return \App\Factories\SeasonFactory
*/
public static function factory()
{
return \Facades\App\Factories\SeasonFactory::instance();
}
}
<?php
namespace App\Factories;
class SeasonFactory extends Factory
{
//
public function model()
{
return factory(Season::class, [
//
]);
}
}
<?php
use App\Season;
//
$season = Season::factory()->withContestants(20)->create();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment